Redux 应用程序中每个 reducer 调用的深度复制状态的缺点是什么?

IT技术 reactjs redux react-redux
2022-07-22 01:14:13

state每次调用 reducer 函数时,在 Redux 应用程序中对 appReducer 进行深拷贝是否有任何副作用?

我问是因为 Redux 状态的不可变更新模式文档要更新状态上的嵌套对象,您应该浅复制嵌套属性并更新它。

我很好奇在每个动作调用中对状态进行深度复制会有什么副作用。

这是一些伪代码例如

export default function appReducer(state = initialState, action){
let copiedState = JSON.parse(JSON.stringify(state))
switch(action){
  case action.UPDATE_NESTED_PROPERTY:
     copiedState.thing.anotherThing = somethingNew;
     return copiedState;
  case action.UPDATE_SOME_OTHER_NESTED_PROPERTY:
     copiedState.differentThing.nestedProperty = "updated";
     return copiedState;
  default:
     return state;
  }
}

总是深度复制状态然后返回它的方法有什么不好?我还没有看到这样做,所以我假设它有问题。如果状态是一个巨大的对象,那么我确信每次都进行深度复制可能会出现性能问题。但这会导致其他问题吗?

1个回答

深度复制状态将导致重新创建所有 jsx,React 必须比较整个虚拟 dom 并可能重新渲染 DOM。重新渲染 DOM 是 Web 应用程序中最昂贵的操作之一,当您可以防止这种情况发生时,您应该这样做。

当一个动作被调度并且reducer返回一个新状态时,所有传递给的回调都会useState被调用,当它们返回与上次不同的值时,组件将重新创建jsx。然后 React 会将该 jsx 与上次进行比较,并可能重新绘制 DOM。

假设我有一个这样的容器:

const Container = React.memo(function Container({ id }) {
  const dispatch = useDispatch();
  //only if id changes will it re create the selector
  const selectItem = React.useMemo(
    () => createSelectItem(id),
    [id]
  );
  const item = useSelector(selectItem);
  //create remove function only when item has changed
  const remove = React.useCallback(
    //removeItem is an action creator
    () => dispatch(removeItem(item)),
    [item, dispatch]
  );
  //render component only when item changes
  return <Component item={item} remove={remove} />;
});

如果您在每个分派的操作上重新创建整个状态(深拷贝),那么该代码中的任何优化都不会做任何事情。更糟糕的是,item改变的所以remove被重新创建,这意味着Component它将在 DOM 中重新呈现,因为处理函数发生了变化,即使item实际上可能没有改变它只是因为你深度复制了状态而改变了。