реакция useState не обновляется должным образом, когда она вызывается внутри обратного вызова

Я собираюсь посчитать загруженные apis. Я использовал функциональную составляющую.

function Screen(props) {
    const [count, setCount] = useState(0)
    useEffect(() => {
        loadData();
        () => { return null; }
    }, [])
    const loadData = () => {
        axios({ url: API_BASE_URL + 'countries', method: 'get' }).then((res)=>{
            setCount(count+1)
        })
        axios({ url: API_BASE_URL + 'regions', method: 'get' }).then((res)=>{
            setCount(count+1)
        })
    }
    useEffect(() => {
        console.info(count)  // this shows 0, 1, it never be 2
    }, [count])
    return <div></div>
}

что не так с моим кодом? Я думаю, он должен напечатать 2 наконец Спасибо


person Nomura Nori    schedule 16.11.2020    source источник


Ответы (1)


count захватывается как 0 замыканиями, которые вы передаете then. Фактически вы звоните setCount(0 + 1). Подробное объяснение можно найти здесь: https://overrected.io/a-complete-guide-to-useeffect/

Вот обновленная версия вашего кода, которая устраняет проблемы:

import React, { useCallback, useEffect, useState } from 'react';

const fakeApi = (delay = 400, val = null): Promise<typeof val> => new Promise(resolve => {
  setTimeout(resolve, delay, val);
});

const Count: React.FC = () => {
  const [count, setCount] = useState(0);

  const loadData = useCallback(() => {
    fakeApi(1000).then(() => {
      setCount(count => count + 1); // use the function form of setState to get the current state value without being *dependent* on it.
    });

    fakeApi(2000).then(() => {
      setCount(count => count + 1); // same as above.
    });
  }, []); // no dependencies => loadData is constant

  useEffect(() => {
    loadData();
  }, [loadData]); // dependent on loadData, but that changes only once (first render, see above).

  // note: you could move loadData inside the effect to reduce some code noise. Example:
  //
  // useEffect(() => {
  //   const loadData = () => {
  //     fakeApi(1000).then(() => {
  //       setCount(count => count + 1);
  //     });
  //
  //     fakeApi(2000).then(() => {
  //       setCount(count => count + 1);
  //     });
  //   };
  //
  //   loadData();
  // }, []);

  return (
    <div>{count}</div>
  );
};

export default Count;

Демо: https://codesandbox.io/s/focused-sun-0cz6u?file=/src/App.tsx

person Yoshi    schedule 16.11.2020