reactjs - Redux Toolkit `useAppSelector` 值在未更新时会导致渲染
问题描述
背景
标题可能令人困惑,但为了解释,我将切片与 Redux Toolkit 一起使用以管理状态。这些切片为我的地图应用程序保存各种状态值。具体来说,我在渲染方面遇到的两个问题是单击位置(称为focusedPosition
鼠标坐标mouseCoords
)。这些切片中的每一个都包含一个lat
和lng
值。使用react-leaflet
,我有地图事件,focusedPosition
每当用户单击地图以显示弹出窗口时,它们都会更新。我还有一个事件来捕获mouseCoords
要显示在地图一角的事件。但是,由于某种原因,任何订阅focusedPosition
更新的组件都会在鼠标移动时重新渲染——即使它没有订阅mouseCoords
. 这会导致多个问题,包括性能问题以及映射弹出窗口闪烁,因为它们会在鼠标移动时不断重新渲染。如果我在 react-leaflet 中注释掉mousemove
事件,问题就会停止,因为该值不再更新,但这不是一个选项,因为我真的需要捕获这些鼠标坐标。
我怎样才能确定为什么这两个值会以某种方式联系起来,我该如何解决这个问题?
适用的代码如下,以及一个代码沙箱
store.ts
export const store = configureStore({
reducer: {
focusedPosition: focusedPositionReducer,
mouseCoords: mouseCoordsReducer,
}
})
// Export AppDispatch
// Export RootState
// Export AppThunk
聚焦位置切片.tsx
interface FocusedPositionState {
lat: number | null
lng: number | null
}
const initialState: FocusedPositionState = {
lat: null,
lng: null,
}
export const focusedPositionSlice = createSlice({
name: 'focusedPosition',
initialState,
reducers: {
clearFocusedPosition: state => {
state.lat = null
state.lng = null
},
setFocusedPosition: (state, action: PayloadAction<FocusedPositionState>) => {
state.lat = action.payload.lat
state.lng = action.payload.lng
}
}
})
// Export actions
// Export getFocusedPosition selector
// Export default reducer
mouseCoordsSlice.tsx
interface MouseCoordsState {
lat: number
lng: number
}
const initialState: MouseCoordsState = {
lat: 0,
lng: 0,
}
export const mouseCoordsSlice = createSlice({
name: 'mouseCoords',
initialState,
reducers: {
setMouseCoords: (state, action: PayloadAction<MouseCoordsState>) => {
state.lat = action.payload.lat
state.lng = action.payload.lng
}
}
})
// Export actions
// Export getMouseCoords selector
// Export default reducer
解决方案
您getFocusedPosition
的选择器在每次调用 reducer 时都会创建一个新对象。
由于 react-redux 会在何时重新渲染,oldSelectorResult !=== newSelectorResult
并且这些对象在引用上不相等,这将导致重新渲染。
您可以选择完整的切片状态(如果将来您添加更多道具,可能会出现过度使用的风险)
export const getFocusedPosition = (state: RootState) => state.focusedPosition;
或创建一个仅在输入值更改时返回新对象的记忆选择器(请参阅https://redux.js.org/recipes/computing-derived-data):
export const getFocusedPosition = createSelector(
state => state.focusedPosition.lat,
state => state.focusedPosition.lng,
(lat, lng) => ({ lat, lng })
)
或者您只需单独订阅这两个值:
const lat = useAppSelector(state => state.focusedPosition.lat)
const lng = useAppSelector(state => state.focusedPosition.lng)
所有这些都在useSelector
文档中进一步讨论:https ://react-redux.js.org/api/hooks#equality-comparisons-and-updates
推荐阅读
- typescript - 在函数中使用条件 Typescript 类型进行车削操作
- firebase - 如何按学科名称计算分值?
- http - Web 浏览器如何识别 HTTP 请求内容长度
- android - 使用 firebase 和颤振在应用程序中注册时出错
- python - 如何在 matplotlib 子图中迭代轴
- javascript - 我正在实现图像预览功能,但在此期间无法重置相关文件输入
- python - 带有两个日期的 django 过滤器
- mysql - 如何在MYSQL中查找哪个用户删除了存储过程
- angular - 如何根据用户输入添加表单控件名称
- jasper-reports - Jasper/iReport - 超长文本无法在 excel 导出中正确显示