【问题标题】:Why are all the PureComponent children of a container updating when only one child's state is modified in the container's state tree?为什么在容器的状态树中只修改了一个子节点的状态时,容器的所有 PureComponent 子节点都会更新?
【发布时间】:2025-11-24 14:50:01
【问题描述】:

学习 React 和 Redux。我正在使用 Redux 示例,目前正在查看 todo-with-undo 示例(认为不可能设置沙箱或其他东西)。在此设置中,有一个容器组件 (TodoList) 和它的子组件 (Todo)。

我将 Todo 从一个功能组件修改为 PureComponent 类,因此如果所有的 prop 引用都相同,shouldComponentUpdate() 将返回 false,因此组件不应更新(但它们仍会重新渲染???) .

添加代码在子组件使用 componentDidUpdate() 方法更新时进行记录,并在重新渲染时进行记录,这表明每次将新的 Todo 添加到容器中时,所有元素都会更新并重新渲染 -即使是 PureComponents - 每个孩子的新旧道具的浅层比较应该为新的或更新的孩子返回 false。

作为 Redux 构建的示例,我怀疑他们是否错误地更新了商店(不是以不可变的方式),因为这是他们概念的重点,所以我相信我没有完全理解某些东西 -> 有人请帮忙.. .

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    因为<TodoList> 正在向每个孩子传递一个新的回调函数引用:

    export default class TodoList extends Component {
      render() {
        return (
          <ul>
            {this.props.todos.map((todo, index) =>
              <Todo {...todo}
                    key={index}
                    onClick={() => this.props.onTodoClick(index)} />
            )}
          </ul>
        );
      }
    }
    

    这总是会导致子级重新渲染,即使它试图根据道具比较优化渲染。

    【讨论】:

    【解决方案2】:

    PureComponent 并不意味着它不会更新,它只是意味着 React 将通过实现带有浅 prop 和状态比较的 shouldComponentUpdate 来为你处理 prop 和状态的比较。

    【讨论】:

    • 我明白,我应该更清楚,但是除了更新的或新的孩子之外,浅比较应该返回 true - 我没有实现控制这个的 reducer(状态更新),redux开发人员做到了,所以应该没问题。
    • 干杯,该链接有助于我理解 PureComponents 如何实现 shouldComponentUpdate(),但我认为它对这种情况没有帮助。在 todo 演示中,TodoList 获取一个字符串数组。数组的引用随例如变化而变化新的 todo(不变性),所以 TodoList 重新渲染,好吧。这导致对子项进行更新检查,仅给出的道具是一个字符串(JS中的原始值),并且反应浅比较直接比较这些旧值和新值?所以如果不变应该返回false?我认为这是正确的,但它仍然不符合应用程序的行为,所以...
    • 当你切换 todo 时,你正在使用 map 创建一个新的 todo 数组,这就是导致重新渲染的原因,你应该使用 React.memo 来防止 todo 更新,看看这个:codesandbox.io/s/todos-with-undo-e049t
    • React.memo 和功能组件正是我所需要的,非常感谢您帮助我理解,但仍然不知道为什么 PureComponent 不应该工作。我知道 map 函数会给出一个带有新引用的新数组,TodoList 将重新渲染,并诱导子节点的更新,但是子节点只是被赋予字符串,如果它们与以前的字符串相同, shouldComponentUpdate() 应该返回假的吧?我会阅读更多,也许会点击。
    最近更新 更多