簡體   English   中英

如何使用 useState 在反應功能組件的循環中正確設置 state

[英]How to correctly set state in a loop in react functional component using useState

考慮一下我正在上傳一堆文件,並且我正在嘗試跟蹤正在進行的文件,以便每當上傳完成時,我都會減少我的 state 直到所有文件都完成,最后我將上傳的 state 更改為false :(這里我做了一個sleep function 來模擬上傳過程)。

import React, { useState} from "react";

const sleep = (ms, dev =1 ) => {
  const msWithDev = (Math.random() * dev + 1) * ms
  return new Promise(resolve => setTimeout(resolve, msWithDev))
}

function Counter() {
  const [, setSortEnabled] = useState(true)
  const [count, setCount] = useState(0)
  const arr = [1, 2, 3, 4, 5]

  const upload = async () => {
    await sleep(1000)
    setCount(c => c - 1)

      console.log(`count state: ${count}`)

      if (count === 0) {
        console.warn('Sort set to enabled again.')
        setSortEnabled(true)
    }
  }


  const onClick = ()  => {
    console.warn('Sort set to disabled.')
      arr.forEach(item => {
        setCount(c => c + 1)
        console.error(count)
        upload()
      })
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;

問題在於upload

function `console.log(\`count state: ${count}\`)`

始終記錄0 ,這意味着 state 從未更新過。

我在這里做錯了什么?

這意味着 state 從未更新過

它確實得到了更新,你只是因為閉包而記錄了陳舊的價值

閉包是捆綁在一起(封閉)的 function 及其周圍 state(詞法環境)的組合。 換句話說,閉包使您可以從內部 function 訪問外部函數的 scope。

要修復它,請使用setState 功能更新

const onClick = () => {
  console.warn("Sort set to disabled.");
  arr.forEach((item) => {
    setCount((c) => {
      console.error(c);
      return c + 1;
    });
    upload();
  });
};

編輯 spring-sky-sw8gv

而不是依靠計數,您必須使用Promise.all等待所有文件上傳。 在您的情況下,計數是從關閉中收到的,因此即使更新了 state,計數變量仍然不受影響。

您可以使用 Promise.all 來實現上述邏輯

function Counter() {
  const [, setSortEnabled] = useState(true)
  const arr = [1, 2, 3, 4, 5]

  const upload = async () => {
    await sleep(1000);
  }


  const onClick = async ()  => {
    console.warn('Sort set to disabled.')
      const promises = arr.map(item => {
        console.error(count)
        return upload()
      });
      await Promise.all(promises);
      console.warn('Sort set to enabled again.')
      setSortEnabled(true)
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;

更新:

要解決計數 state 的關閉問題,您可以使用 refs 和 useEffect。 然而,它是一種解決方法,不應該是首選

import React, { useState} from "react";

const sleep = (ms, dev =1 ) => {
  const msWithDev = (Math.random() * dev + 1) * ms
  return new Promise(resolve => setTimeout(resolve, msWithDev))
}

function Counter() {
  const [, setSortEnabled] = useState(true)
  const [count, setCount] = useState(0)
  const arr = [1, 2, 3, 4, 5]
  const countRef = useRef(count);
  useEffect(() => {
     countRef.current = count;
  }, [count ]);
  const upload = async () => {
    await sleep(1000)
    setCount(c => c - 1)

      console.log(`count state: ${count}`)

      if (countRef.current === 0) {
        console.warn('Sort set to enabled again.')
        setSortEnabled(true)
    }
  }


  const onClick = ()  => {
    console.warn('Sort set to disabled.')
      arr.forEach(item => {
        setCount(c => c + 1)
        upload();
      })
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM