Window 调整大小 - React + Redux
Window Resize - React + Redux
我是 Redux 的新手,我想知道是否有人对处理 window 调整大小等非 React 事件的最佳实践有一些提示。在我的研究中,我从 React 官方文档中找到了这个 link:
https://facebook.github.io/react/tips/dom-event-listeners.html
我的问题是,在使用 Redux 时,我应该将 window 大小存储在我的 Store 中还是应该将其保留在我的单独组件状态中?
好问题。我想在我的商店里放一个 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));
});
媒体查询
如果您的应用采用更二元的屏幕尺寸视图(例如 large/small),您可能更愿意改用媒体查询。例如
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 代码。它们看起来很明显。)
这种方法的一个缺点是商店可能会被初始化为错误的值,而我们依赖媒体查询在商店初始化后设置正确的值。除了将媒体查询推送到 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
状态的任何其他内容都会丢失。
使用redux-responsive 来处理应用程序的响应状态。它使用 store enhancer 通过自己的 reducer 管理商店状态(通常称为 'browser')的专用区域(属性),这样您就不必向文档隐式添加事件侦听器对象。
您需要做的就是将 browser.width、browser.height 等映射到组件的道具。
请注意,只有 redux-responsive 中定义的减速器负责更新这些值。
我有一个类似的情况,我需要 window 尺寸用于响应以外的目的。根据 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 调度作为参数的侦听器函数,并使用它来调度所需的操作。有关示例,请参见参考资料。但是目前接受的答案几乎涵盖了这种情况
我是 Redux 的新手,我想知道是否有人对处理 window 调整大小等非 React 事件的最佳实践有一些提示。在我的研究中,我从 React 官方文档中找到了这个 link: https://facebook.github.io/react/tips/dom-event-listeners.html
我的问题是,在使用 Redux 时,我应该将 window 大小存储在我的 Store 中还是应该将其保留在我的单独组件状态中?
好问题。我想在我的商店里放一个 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));
});
媒体查询
如果您的应用采用更二元的屏幕尺寸视图(例如 large/small),您可能更愿意改用媒体查询。例如
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 代码。它们看起来很明显。)
这种方法的一个缺点是商店可能会被初始化为错误的值,而我们依赖媒体查询在商店初始化后设置正确的值。除了将媒体查询推送到 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
状态的任何其他内容都会丢失。
使用redux-responsive 来处理应用程序的响应状态。它使用 store enhancer 通过自己的 reducer 管理商店状态(通常称为 'browser')的专用区域(属性),这样您就不必向文档隐式添加事件侦听器对象。
您需要做的就是将 browser.width、browser.height 等映射到组件的道具。 请注意,只有 redux-responsive 中定义的减速器负责更新这些值。
我有一个类似的情况,我需要 window 尺寸用于响应以外的目的。根据 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 调度作为参数的侦听器函数,并使用它来调度所需的操作。有关示例,请参见参考资料。但是目前接受的答案几乎涵盖了这种情况