窗口调整大小 - React + Redux

时间:2016-01-28 22:49:50

标签: javascript reactjs redux

我是Redux的新手,我想知道是否有人提供有关处理非React事件(如窗口大小调整)的最佳做法的一些提示。在我的研究中,我从官方的React文档中找到了这个链接: https://facebook.github.io/react/tips/dom-event-listeners.html

我的问题是,在使用Redux时,我应该将窗口大小存储在我的商店中,还是应该将其保持在我的个别组件状态?

3 个答案:

答案 0 :(得分:49)

好问题。我喜欢在我的商店里有一个ui部分。减速器可能如下所示:

const initialState = {
    screenWidth: typeof window === 'object' ? window.innerWidth : null
};

function uiReducer(state = initialState, action) {
    switch (action.type) {
        case SCREEN_RESIZE:
            return Object.assign({}, state, {
                screenWidth: action.screenWidth
            });
    }
    return state;
}

这个动作非常漂亮。 (SCREEN_RESIZE是一个常量字符串。)

function screenResize(width) {
    return {
        type: SCREEN_RESIZE,
        screenWidth: width
    };
}

最后,您将它与事件侦听器连接在一起。我会将以下代码放在您初始化store变量的位置。

window.addEventListener('resize', () => {
    store.dispatch(screenResize(window.innerWidth));
});

媒体查询

如果您的应用采用更加二进制的屏幕尺寸视图(例如大/小),您可能更愿意使用媒体查询。 e.g。

const mediaQuery = window.matchMedia('(min-width: 650px)');

if (mediaQuery.matches) {
    store.dispatch(setLargeScreen());
} else {
    store.dispatch(setSmallScreen());
}

mediaQuery.addListener((mq) => {
    if (mq.matches) {
        store.dispatch(setLargeScreen());
    } else {
        store.dispatch(setSmallScreen());
    }
});

(这次我会省略动作和减速器代码。它们看起来很明显。)

这种方法的一个缺点是可能使用错误的值初始化存储,并且我们依赖媒体查询在初始化存储之后设置正确的值。如果没有将媒体查询推送到reducer文件本身,我不知道最好的解决方法。欢迎反馈。

更新

现在我考虑一下,你可以通过做类似下面的事情来解决这个问题。 (但要注意,我没有对此进行测试。)

const mediaQuery = window.matchMedia('(min-width: 650px)');

const store = createStore(reducer, {
    ui: {
        largeScreen: mediaQuery.matches
    }
});

mediaQuery.addListener((mq) => {
    if (mq.matches) {
        store.dispatch(setLargeScreen());
    } else {
        store.dispatch(setSmallScreen());
    }
});

更新II:最后一种方法的缺点是ui对象将替换整个ui状态而不仅仅是largeScreen字段。无论最初的ui状态是什么,都会丢失。

答案 1 :(得分:6)

使用redux-responsive来处理应用程序的响应状态。它使用商店增强器通过自己的reducer管理商店状态的专用区域(属性)(通常称为浏览器'),因此您不必隐式添加事件侦听器到文档对象。

您需要做的就是将browser.width,browser.height等映射到组件的道具。 请注意,只有redux-responsive中定义的reducer负责更新这些值。

答案 2 :(得分:1)

我有一个类似的情况,我需要窗口大小用于响应以外的目的。根据{{​​3}},你也可以使用redux-thunk:

function listenToWindowEvent(name, mapEventToAction, filter = (e) => true) {
  return function (dispatch) {
    function handleEvent(e) {
      if (filter(e)) {
        dispatch(mapEventToAction(e));
      }
    }

    window.addEventListener(name, handleEvent);

    // note: returns a function to unsubscribe
    return () => window.removeEventListener(name, handleEvent);
  };
}

// turns DOM event into action,
// you can define many of those
function globalKeyPress(e) {
  return {
    type: 'GLOBAL_KEY_PRESS',
    key: e.key
  };
}

// subscribe to event
let unlistenKeyPress = store.dispatch(listenToWindowEvent('keypress', globalKeyPress));
// eventually unsubscribe
unlistenKeyPress();

虽然实际上,如果你的用例很简单,你甚至不需要使用thunk函数。只需创建一个侦听器函数,将Redux调度作为参数并使用它来分派所需的操作。有关示例,请参阅参考资料。但目前接受的答案几乎涵盖了这种情况