【发布时间】:2019-08-22 10:26:15
【问题描述】:
当状态处于钩子中时,它可能会变得陈旧并泄漏内存:
function App() {
const [greeting, setGreeting] = useState("hello");
const cb = useCallback(() => {
alert("greeting is " + greeting);
}, []);
return (
<div className="App">
<button onClick={() => cb()}>Click me</button>
<p>
Click the button above, and now update the greeting by clicking the one
below:
</p>
<button onClick={() => setGreeting("bye")}>
Update greeting
</button>
<p>Greeting is: {greeting}</p>
<p>
Now click the first button again and see that the callback still has the
old state.
</p>
</div>
);
}
演示:https://codesandbox.io/s/react-hook-stale-datamem-leak-demo-9pchk
这样做的问题是,如果我们按照 Facebook 的建议始终列出所有依赖项,并确保我们没有陈旧数据或内存泄漏(如上面的例子):
const [state, setState] = useState({
number: 0
});
const fetchRandomNumber = useCallback(async () => {
if (state.number !== 5) {
const res = await fetch('randomNumber');
setState(v => ({ ...v, number: res.number }));
}
}, [setState, state.number]);
useEffect(() => {
fetchRandomNumber();
}, [fetchRandomNumber]);
由于 Facebook 说我们应该将 fetchRandomNumber 列为依赖项(react-hooks/exhaustive-deps ESLint 规则),我们必须使用 useCallback 来维护引用,但它在每次调用时重新生成,因为它取决于 state.number 并更新它。
这是一个人为的例子,但我在获取数据时遇到过很多次。在这种情况下是否有解决方法或 Facebook 有问题?
【问题讨论】:
-
fetchSomething没有改变,不是吗?它不是状态,它只是你正在调用的一个方法,那么你为什么将它列在依赖数组中呢?只需使用一个空数组即可使用一次效果。 -
我同意,但 Facebook 团队认为应该始终列出所有部门,默认情况下这是一个 lint 错误:github.com/facebook/create-react-app/issues/6880
-
I think you're safe to use the empty array in this case 因为
fetchSomething不依赖组件范围内的任何东西(我可以看到)。 -
不幸的是,这不是真的,因为读取状态它将引用一个旧值(内存泄漏也是),除非状态是一个原始值 - 请参阅codesandbox.io/s/admiring-ganguly-9pchk
标签: javascript reactjs react-hooks