React Hooks 详尽的异步无限循环

hed*_*cox 8 typescript reactjs react-hooks eslint-plugin-react-hooks

我有以下组件:

\n
import React, { useState, useEffect } from "react";\n\nconst App = () => {\n    const [data, setData] = useState<null | any[]>(null);\n    const [checked, setChecked] = useState(false);\n    const [loading, setLoading] = useState(false);\n\n    useEffect(() => {\n        setLoading(true);\n\n        (async () => {\n            if (data) {\n                // Could do something else here if data already exsisted\n                console.log("Data exists already");\n            }\n\n            const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });\n            const json = await ret.json();\n            setData(json);\n            setLoading(false);\n        })();\n\n    }, [checked]);\n\n    return (\n        <>\n            <h1>useEffect Testing {loading && " \xe2\x8c\x9b"}</h1>\n            <hr />\n            <input type="checkbox" checked={checked} onChange={(e) => setChecked(e.target.checked)} />\n            <pre style={{ fontSize: "0.8em" }}>{JSON.stringify(data)}</pre>\n        </>\n    );\n};\n\nexport default App;\n\n
Run Code Online (Sandbox Code Playgroud)\n

目前,我的if(data)方法毫无意义,但是如果我想检查当前data状态,然后根据状态运行异步函数,eslint(react-hooks/exhaustive-deps)会告诉我钩子缺少data依赖项,事实确实如此。当我将数据添加到依赖项列表中导致无限循环时,问题就出现了。

\n

知道如何解决这个问题吗?感觉它应该是相当简单的模式,但是我发现的所有内容都建议使用扩展setState(prev => prev + 1)重载,这在这种情况下对我没有帮助。

\n

Die*_*sel 3

您正在设置data并读取它的效果。这将导致无限循环,除非您手动停止它。这里有一些解决方案。

如果有数据则返回而不是修改:

useEffect(() => {
    setLoading(true);

    (async () => {
        if (data) {
            // Could do something else here if data already exsisted
            console.log("Data exists already");
            return;
        }

        const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
        const json = await ret.json();
        setData(json);
        setLoading(false);
    })();

}, [checked, data]);
Run Code Online (Sandbox Code Playgroud)

data消除对设置它的效果的依赖(我会做什么):

useEffect(() => {
    setLoading(true);

    (async () => {
        const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
        const json = await ret.json();
        setData(json);
        setLoading(false);
    })();

}, [checked]);

useEffect(() => {
        if (data) {
            // Could do something else here if data already exsisted
            console.log("Data changed and exists!");
        }
}, [data]);
Run Code Online (Sandbox Code Playgroud)

或者您可以手动执行一些操作来停止无限循环。

useEffect(() => {
    if (loading || data) {
      console.log('Do something with loading or data, but do not modify it!')
      return;
    }

    setLoading(true);

    (async () => {
        const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
        const json = await ret.json();
        setData(json);
        setLoading(false);
    })();
}, [checked, data]);
Run Code Online (Sandbox Code Playgroud)