【问题标题】:Window Resize - React + Redux窗口调整大小 - React + Redux
【发布时间】:2016-01-28 22:49:50
【问题描述】:

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

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

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    好问题。我喜欢在我的商店中有一个 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));
    });
    

    媒体查询

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

    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());
        }
    });
    

    (这次我将省略 action 和 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());
        }
    });
    

    更新二:最后一种方法的缺点是ui 对象将替换整个ui 状态,而不仅仅是largeScreen 字段。初始ui 状态的任何其他内容都会丢失。

    【讨论】:

    • 我不确定这是否是一个好的解决方案。我目前遇到同样的问题,正在寻找一种处理屏幕大小的好方法。 redux 的关键概念之一是可序列化状态。诸如导入/导出状态或时间旅行之类的功能通过此功能成为可能。但是,如果我恢复以前存储的状态或进行时间旅行,则状态中的值与我的实际窗口大小不同步。这似乎不是“单一事实来源”的意图。
    • 这是一个合理的观点。这种方法有其缺陷。存储的状态将 (a) 复制存储在窗口对象中的信息和 (b) 反映但不驱动 UI 更改。但是我们需要一种方法来提醒应用程序的其余部分注意浏览器状态的变化,而 Redux 为我们提供了这一点。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      我有一个类似的情况,我需要窗口大小来实现响应性以外的目的。根据this,你也可以使用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 调度为参数的侦听器函数,并使用它来调度所需的操作。有关示例,请参见参考资料。但目前接受的答案几乎涵盖了这种情况

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-11
        • 2020-05-30
        • 2019-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-27
        • 2012-04-07
        相关资源
        最近更新 更多