【问题标题】:State is not updating in useEffect why?状态在 useEffect 中没有更新,为什么?
【发布时间】:2022-01-16 17:55:00
【问题描述】:

我正在尝试制作一个加密价格跟踪网站。我在每 10 秒更新一次 coinList 变量 prevData 变量后获取数据。我也想访问 useEffect 中的 prevData 变量,但在其中变量没有更新,它的值仍然是 []。但是,如果我在 useEffect 之外使用 prevData,数据会发生变化,我可以使用它。

我只想要 prevData 在 useEffect 中更新的值。

function App() {
    const [coinsList, setCoinsList] = useState([]);
    const [prevData, setPrevData] = useState([]);
    let [width, setWidth] = useState(window.innerWidth)
    useEffect(() => {
        async function fetchData() {
            const response = await fetch('api key').then(res => res.json())
setCoinsList(res);
setPrevData(res);
        }
        fetchData()
        async function fetchData2() {
            const res = await fetch('api key').then(res => res.json())
            for (let i = 0; i < prevData.length; i++) {
                if (res[i].current_price > prevData[i].current_price) {
                    let coin = document.getElementById(`${prevData[i].id}`)
                    coin.classList.add('green')
                    console.log(coin)
                    // setTimeout(() => {
                    //     coin.classList.remove('green')
                    // }, 1000)
                } else if (res[i].current_price < prevData[i].current_price) {
                    let coin = document.getElementById(`${prevData[i].id}`)
                    coin.classList.add('red')
                    console.log(coin)

                    // setTimeout(() => {
                    //     coin.classList.remove('red')
                    // }, 1000)
                } else {
                    let coin = document.getElementById(`${prevData[i].id}`)
                    console.log(coin)
                    coin.classList.add('blue')
                    // setTimeout(() => {
                    //     coin.classList.remove('blue')
                    // }, 1000)
                }
            }
            setPrevData(res);
            setCoinsList(res);
        }
        setInterval(() => {
            fetchData2()
            console.log(prevData) // it is not updating
        }, 10000)
    }, [])
    useEffect(() => {
        window.addEventListener('resize', () => {
            setWidth(window.innerWidth)
        })
    }, [window.innerWidth])
    console.log(prevData) // it is updating 

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect use-state


    【解决方案1】:

    fetchData2 中,您拥有prevData 状态的陈旧外壳。它在区间回调范围内被关闭。

    一种补救方法是使用 React ref 和一个额外的 useEffect 挂钩来缓存可以在 fetchData2 回调中访问的 prevData 状态的副本。

    function App() {
      const [coinsList, setCoinsList] = useState([]);
      const [prevData, setPrevData] = useState([]);
    
      const prevDataRef = React.useRef(prevData);
    
      useEffect(() => {
        prevDataRef.current = prevData;
      }, [prevData]);
    
      ...
    
      useEffect(() => {
        ...
        async function fetchData2() {
          const prevData = prevDataRef.current; // <-- grab current value
    
          const res = await fetch('api key').then(res => res.json());
    
          for (let i = 0; i < prevData.length; i++) {
            if (res[i].current_price > prevData[i].current_price) {
              let coin = document.getElementById(`${prevData[i].id}`);
              coin.classList.add('green');
            } else if (res[i].current_price < prevData[i].current_price) {
              let coin = document.getElementById(`${prevData[i].id}`);
              coin.classList.add('red');
            } else {
              let coin = document.getElementById(`${prevData[i].id}`);
              coin.classList.add('blue');
            }
          }
          setPrevData(res);
          setCoinsList(res);
        }
    
        setInterval(() => {
          fetchData2();
        }, 10000)
    }, []);
    

    【讨论】:

    • 感谢您的帮助 现在我的代码可以按照我的意愿完美运行。但是你能解释一下为什么它不起作用吗?我没有得到 prevData 正在关闭,它在 setinterval 上关闭 -
    • @Nimish 正确,初始 prevData 值在 setInterval 回调范围内被关闭。这意味着您创建一个匿名回调函数并将其传递给setInterval。这是 that 函数的特定副本或“实例”,其中复制了所有使用的变量。此间隔回调的相同副本/实例被重复使用且永不更新,因此内部复制的变量也永不更新。 React ref 是一个外部(回调范围)可变的对象。
    • 这意味着我们在setInterval回调函数中添加的任何东西,无论它当时的状态是什么,它只会重复那个状态,不会根据原来的状态更新?
    • @Nimish Affirmative.
    【解决方案2】:

    您在setInterval 范围内的prevData 值上有closure,您可以使用引用来修复它:

    const prevDataRef = useRef();
    
    // Keep the ref updates
    useEffect(() => {
      prevDataRef.current = prevData;
    }, []);
    
    // no closure
    useEffect(() => {
      setInterval(() => {
        fetchData2(); // use prevDataRef.current
        console.log(prevDataRef.current); // updated
      }, 10000);
    }, []);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      • 2021-08-04
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      相关资源
      最近更新 更多