首頁  >  問答  >  主體

為什麼需要使用功能更新形式的 React useState?

我正在閱讀有關功能更新的 React Hook 文件並查看以下引用:

“ ”和“-”按鈕使用函數形式,因為更新 值基於先前的值

但我看不出需要功能更新的目的是什麼,以及它們與直接使用舊狀態計算新狀態之間有什麼區別。

為什麼 React useState Hook 的更新器功能需要功能更新形式? 有哪些範例可以讓我們清楚地看到差異(因此使用直接更新會導致錯誤)?

例如,如果我從文件中更改此範例

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}

直接更新count

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </>
  );
}

我看不出行為有任何差異,也無法想像計數不會更新(或不是最新的)的情況。因為每當計數發生變化時,都會呼叫 onClick 的新閉包,捕獲最新的 count

P粉155551728P粉155551728334 天前639

全部回覆(2)我來回復

  • P粉818125805

    P粉8181258052023-10-23 10:02:44

    我最近偶然發現了這個需求。例如,假設您有一個元件,它用一定數量的元素填充一個數組,並且能夠根據某些用戶操作附加到該數組(就像在我的例子中,我一次加載一個提要10 個項目,因為用戶不斷向下滾動螢幕。程式碼看起來有點像這樣:

    function Stream() {
      const [feedItems, setFeedItems] = useState([]);
      const { fetching, error, data, run } = useQuery(SOME_QUERY, vars);
    
      useEffect(() => {
        if (data) {
          setFeedItems([...feedItems, ...data.items]);
        }
      }, [data]);     // <---- this breaks the rules of hooks, missing feedItems
    
    ...
    <button onClick={()=>run()}>get more</button>
    ...

    顯然,您不能只將 feedItems 新增至 useEffect 掛鉤中的依賴項清單中,因為您要在其中呼叫 setFeedItems,因此您會陷入循環。

    功能更新來拯救:

    useEffect(() => {
        if (data) {
          setFeedItems(prevItems => [...prevItems, ...data.items]);
        }
      }, [data]);     //  <--- all good now

    回覆
    0
  • P粉457445858

    P粉4574458582023-10-23 09:44:55

    React 中狀態更新是非同步的。因此,當您下次更新時,count 中可能會有舊值。例如,比較這兩個程式碼範例的結果:

    function Counter({initialCount}) {
      const [count, setCount] = useState(initialCount);
      return (
        <>
          Count: {count}
          <button onClick={() => setCount(initialCount)}>Reset</button>
          <button onClick={() => {
            setCount(prevCount => prevCount + 1); 
            setCount(prevCount => prevCount + 1)}
          }>+</button>
        </>
      );
    }

    function Counter({initialCount}) {
      const [count, setCount] = useState(initialCount);
      return (
        <>
          Count: {count}
          <button onClick={() => setCount(initialCount)}>Reset</button>
          <button onClick={() => {
            setCount(count + 1); 
            setCount(count + 1)}
          }>+</button>
        </>
      );
    }

    回覆
    0
  • 取消回覆