繁体   English   中英

将 React 功能组件与 React.memo 一起使用时如何解决闭包问题?

[英]How to solve closures issue when using React functional component with React.memo?

我在 React.memo 旁边使用了 React 功能组件,但我遇到了一个问题,在我看来,这源于 JavaScript 闭包。 (我也在使用 Immer 来实现不变性,但我相信它不会影响这种情况。)

以下是情况的简化版本:

import React, { useState } from 'react';
import produce from "immer";

const initialData = [
  {id: 1, value: 0},
  {id: 2, value: 0},
  {id: 3, value: 0}
]

const ChildComponent = memo(
  ({ value, onChange }) => (
    <p>
      <input value={value} onChange={onChange} type="number" />
    </p>
  ),
  (prevProps, nextProps) => prevProps.value === nextProps.value
);

const ParentComponent = props => {
  const [data, setData] = useState(initialData);

  const onDataChange = id => event => {
    setData(
      produce(data, draft => {
        const record = draft.find(entry => entry.id === id);
        record.value = event.target.value;
      })
    );
  };

  return data.map(record => (
    <ChildComponent
      key={record.id}
      value={record.value}
      onChange={onDataChange(record.id)}
    />
  ));
};

我正在使用 React.memo 来避免不必要地重新渲染其值没有改变的 ChildComponents,但是通过这种方式 ChildComponent 存储了旧版本的 onChange function,它(在我的理解中由于 JavaScript 闭包)引用了旧版本的数据。

这样做的结果是,当我最初更改第一个 ChildComponent 的值,然后更改另一个 ChildComponent 的值时,第一个 ChildComponent 的值恢复为初始值。

这个沙箱中可以找到这种情况的再现。

在搜索 web 后,我发现解决此问题的方法是在 onChange function 中使用 ref 来获取最新数据,如下所示:

const ParentComponent = props => {
  const [data, setData] = useState(initialData);
  const dataRef = useRef();
  dataRef.current = data;

  const onDataChange = id => event => {
    setData(
      produce(dataRef.current, draft => {
        const record = draft.find(entry => entry.id === id);
        record.value = event.target.value;
      })
    );
  };

  return data.map(record => (
    <ChildComponent
      key={record.id}
      value={record.value}
      onChange={onDataChange(record.id)}
    />
  ));
};

可以在此处找到具有此解决方案的沙箱。

这解决了这个问题。 但我想问,这是一个正确的解决方案吗? 还是我以错误的方式使用 React 和 React Hooks?

尽管使用引用是一种有效的解决方案,但您应该使用功能性setState

如果使用以前的 state 计算新的 state,则可以将 function 传递给 setState。 function 将接收先前的值,并返回更新的值。

const onDataChange = id => event => {
  event.persist();
  setData(data =>
    produce(data, draft => {
      const record = draft.find(entry => entry.id === id);
      record.value = event.target.value;
    })
  );
};

编辑 sparkling-haze-e9y22

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM