![](/img/trans.png)
[英]How to know if props have changed when using React.memo() with a functional Component
[英]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;
})
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.