处于挂起状态时,它可能会过时并泄漏内存:
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错误?
答案 0 :(得分:3)
使用状态设置器的功能形式:
const fetchData = useCallback(async () => {
const res = await fetch(`url?page=${page}`);
setData((data) => ([...data, ...res.data]));
setPage((page) => page + 1);
}, [setData, setPage]);
现在您不需要数据和页面作为您的部门
您还可以使用ref仅在mount上运行效果:
const mounted = useRef(false);
useEffect(() => {
if(!mounted.current) {
fetchSomething();
mounted.current = true;
}
return () => { mounted.current = false }
}, [fetchSomething]);
还有
const fetchSomething = useCallback(async () => {
...
}, [setData, setPage, data, page]);
答案 1 :(得分:0)
fetchSomething
在这里不是依赖项。您不想重新触发效果,只在组件安装时才造成一次。那就是useEffect(() => ..., [])
的目的。