Redux 存储中的可变对象是否仅在 Redux 外部发生变异会导致意想不到的副作用?
Can a mutable object in Redux store that is only mutated outside of Redux cause unexpected side effects?
鉴于这种情况:
- Redux 存储中有一个可变对象
- Reducers 不会改变对象;所有 reducer 仍然是没有副作用的纯函数
- 可变对象有时会在 Redux外部 发生变异,例如,通过调用对象本身的方法
我的问题是,这样做是否“安全”,或者是否会产生有问题的副作用,如果是的话是什么以及为什么?特别是,这是否会影响性能,是否会扰乱 Redux 重新计算状态的方式,以及如果对象作为 prop 从 Redux 存储传递给 React 组件,它会扰乱 React 组件的渲染吗?
你应该永远不要改变处于 Redux 状态的值,永远:
这绝对会导致副作用,包括应用程序在需要时可能无法呈现。
如果您指的这个“可变对象”是某种 class 实例或类似的,那也不属于 Redux 存储:
编辑
根据评论中的讨论,以下是我建议如何处理类似 WebGL 上下文的事情:
const SomeParentComponent = () => {
// Use Redux state to decide when we should show this
const showWebGl = useSelector(state => state.ui.showWebGl);
// Standard hooks "forceRender" implementation
const [, forceRender] = useReducer(c => c + 1, 0)
// Ref to hold the WebGL instance
const webGlRef = useRef(null);
useLayoutEffect(() => {
if (showWebGl) {
webGlRef.current = magicallyCreateWebGlInstance();
forceRender(); // have to force a re-render to pass down the ref value
}
return () => {
if (webGlRef.current) {
magicallyDestroyWebGlInstance(webGlRef.current)
}
}
}, [showWebGl])
return (
<MyWebGlContext.Provider value={webGlRef.current>
<RestOfAppGoesHere />
</MyWebGlContext.Provider>
)
}
WebGL 实例本身不属于存储,因为它不是 state,并且不可序列化。 Redux 存储不应该仅仅用作传递任意值的一种方式,尤其是当这些值不是纯 JS 数据时。
这样,Redux 状态仍然决定是否正在创建 WebGL 实例,但实例本身完全存在于 UI 层中,并且组件树的其余部分仍然可以访问。
鉴于这种情况:
- Redux 存储中有一个可变对象
- Reducers 不会改变对象;所有 reducer 仍然是没有副作用的纯函数
- 可变对象有时会在 Redux外部 发生变异,例如,通过调用对象本身的方法
我的问题是,这样做是否“安全”,或者是否会产生有问题的副作用,如果是的话是什么以及为什么?特别是,这是否会影响性能,是否会扰乱 Redux 重新计算状态的方式,以及如果对象作为 prop 从 Redux 存储传递给 React 组件,它会扰乱 React 组件的渲染吗?
你应该永远不要改变处于 Redux 状态的值,永远:
这绝对会导致副作用,包括应用程序在需要时可能无法呈现。
如果您指的这个“可变对象”是某种 class 实例或类似的,那也不属于 Redux 存储:
编辑
根据评论中的讨论,以下是我建议如何处理类似 WebGL 上下文的事情:
const SomeParentComponent = () => {
// Use Redux state to decide when we should show this
const showWebGl = useSelector(state => state.ui.showWebGl);
// Standard hooks "forceRender" implementation
const [, forceRender] = useReducer(c => c + 1, 0)
// Ref to hold the WebGL instance
const webGlRef = useRef(null);
useLayoutEffect(() => {
if (showWebGl) {
webGlRef.current = magicallyCreateWebGlInstance();
forceRender(); // have to force a re-render to pass down the ref value
}
return () => {
if (webGlRef.current) {
magicallyDestroyWebGlInstance(webGlRef.current)
}
}
}, [showWebGl])
return (
<MyWebGlContext.Provider value={webGlRef.current>
<RestOfAppGoesHere />
</MyWebGlContext.Provider>
)
}
WebGL 实例本身不属于存储,因为它不是 state,并且不可序列化。 Redux 存储不应该仅仅用作传递任意值的一种方式,尤其是当这些值不是纯 JS 数据时。
这样,Redux 状态仍然决定是否正在创建 WebGL 实例,但实例本身完全存在于 UI 层中,并且组件树的其余部分仍然可以访问。