首页 > 解决方案 > 在异步循环中设置 useState 挂钩

问题描述

我是 reactJs 的新手。

我试图在异步循环中连接结果,但是出了点问题。setState 没有正确保存,当我打印它时,我可以看到它是一个空数组,我想是因为里面有一个异步调用。

我该如何解决?请给我建议。

function App() {

  const [data, setData] = useState({data:[]});

  const handleChildSubmit = (data) => {
    setData(data);
  }

  return (
    <div>
      <Form onChildSubmit={handleChildSubmit} />
      <Results flights={data} />
    </div>
  );
}

const Form = ( {onChildSubmit} ) => {

    const [dati, setDati] = useState([]);

    const onFormSubmit = async (e) => {
        e.preventDefault();

        // Flights search Parameters
        const data = new FormData(e.target);
        const dateFrom = data.get('dateFrom');
        const dateTo = data.get('dateTo');
        const departureDay = data.get('day');
        const placeFrom = data.get('placeFrom');
        const placeTo = data.get('placeTo');
        let dayDeparture;
        const daysDeparture = getDayOfWeekArray(dateFrom,dateTo,departureDay);

        // Loop of Fly Search in range time
        for(let i=0; i < daysDeparture.length; i++){
            dayDeparture = daysDeparture[i];
            axios.get('https://api.skypicker.com/flights?flyFrom='+placeFrom+'&to='+placeTo+'&dateFrom='+dayDeparture+'&dateTo='+dayDeparture+'&partner=picky')
            .then(res => {

                setDati([...dati, res.data]);
                onChildSubmit(dati);

            })
            .catch(function (error) {
                console.log('error: '+error);
            })
            .finally(function () {
            });
        }

    }

标签: javascriptreactjsasynchronousreact-hooks

解决方案


问题是useState这里为您dati提供了具有特定值的变量。然后你的异步事情发生了,并被setDati()多次调用,但dati在重新呈现表单之前不会改变,然后你再次调用onFormSubmit

你有几个选择。

您只能将结果作为数组添加一次。

const results = []

for(let i=0; i < daysDeparture.length; i++){
    dayDeparture = daysDeparture[i];
    const res = await axios.get('https://api.skypicker.com/flights?flyFrom='+placeFrom+'&to='+placeTo+'&dateFrom='+dayDeparture+'&dateTo='+dayDeparture+'&partner=picky');
    results.push(res.data);
}

// Add all results when all are fetched.
setDati([...dati, ...results])

或者useReducer在您更改状态时可靠地为您提供最新版本的状态,因此您没有过时的数据。

// Something like...

function reducer(state, action) {
  switch(action.type) {
    case 'append':
      return [...state, action.payload]
  }
}

function YourComponent() {
  const [dati, dispatch] = useReducer(reducer, [])

  const onFormSubmit = async (e) => {
    for(let i=0; i < daysDeparture.length; i++){
        dayDeparture = daysDeparture[i];
        const res = await axios.get('https://api.skypicker.com/flights?flyFrom='+placeFrom+'&to='+placeTo+'&dateFrom='+dayDeparture+'&dateTo='+dayDeparture+'&partner=picky')
        dispatch({type: 'append', payload: res.data})
    }
  }
}

推荐阅读