无法在Next.js中使用useState从API响应设置数据

yqlxgs2m  于 2023-06-29  发布在  其他
关注(0)|答案(2)|浏览(187)

我有从API请求中获取数据的函数。我想把这些数据放到状态变量中,但是由于某种原因,它不起作用,当打印状态时,它总是显示空数组。

export default function Buttons({setOptionButtons, sendMessage, places}){

    const [data, setData] = useState(null)
    const [loading, setLoading] = useState(false)
    const [error, setError] = useState(null)
    const [names, setNames] = useState([])
    const [addresses, setAddresses] = useState([])

    useEffect(()=>{
        console.log(data)
    }
    ,[data])

    const pressOption = (input, option) => {
        const fetchData = async () => {
            for (const place of option){
                setLoading(true);
                try {
                    const requests = option.map((place) =>
                        axios.get(`url`)
                    );

                    const responses = await Promise.all(requests);
                    console.log(responses)
                    const items = responses.flatMap((response) => response.data.result.items);
                    const newNames = items.map((item) => item.name);
                    const newAddresses = items.map((item) => item.address_name);

                    setNames((prevNames) => [...prevNames, ...newNames]);
                    setAddresses((prevAddresses) => [...prevAddresses, ...newAddresses]);
                    setError(null);
                    console.log('Hello');
                    console.log(names)
                } catch(error) {
                    setError(error.message)
                } finally {
                    setLoading(false)
                }
            }
        };

        fetchData();
        setOptionButtons(false);
        sendMessage(input);
    }
    return (
///html code
    )
}

我尝试使用promise.all和在fetchData函数之外调用打印。它应该打印我通过useState传递的数据。

gwbalxhn

gwbalxhn1#

我已经自作主张地重构了你的代码,使其能够正常工作,我发现的问题是,在for循环中调用Array.map,这似乎会破坏你的状态。你会发现我在你的函数中添加的注解解释了我为什么做了什么,

function Buttons({ setOptionButtons, sendMessage, places }) {
  const [data, setData] = useState(null);
  const [names, setNames] = useState([]);
  const [addresses, setAddresses] = useState([]);
  
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  const onClick = useCallback(async (input, option) => {
    // early return if the data is already fetching
    if (!!loading) return;
    setError(null);
    setLoading(true);
    try {
      const promises = [];

      // more readable implementation of the for loop
      for (const place of option) {
        promises.push(axios.get("..."));
      }

      // Maybe use `Promise.allSettled` for better error handling
      const responses = await Promise.all(promises);

      const items = responses.flatMap((response) => {
        return response.data.result.items;
      });

      const newNames = items.map((item) => {
        return item.name;
      });

      const newAddresses = items.map((item) => {
        return item.address_name;
      });

      setNames((prev) => [...prev, ...newNames]);
      setAddresses((prev) => [...prev, ...newAddresses]);
    } catch (err) {
      setError(err.message);
    } finally {
      // handle all other updates directly inside the finally block
      setLoading(false);
      setOptionButtons(false);
      sendMessage(input);
    }
  }, [loading, sendMessage, setOptionButtons]);

  useEffect(() => {
    console.log(data);
  }, [data]);

  return <></>;
}

export default Buttons;

另外,你似乎是新的React,一定要看看official documentation的React。他们刚刚更新了他们的整个文档,它真的是信息丰富。

PS:

正如上面的评论所述,你将对你调用的API有相当多的请求,如果你是按请求或带宽付费,我强烈建议在这段代码上使用另一个折射器。

ttygqcqt

ttygqcqt2#

看起来问题出在setOptionButtons(false)这一行,这是异步的。所以我将await添加到这一行,并将其与updateOptionButtons()混洗,以便它等待直到第一个异步函数结束。
此外,最好使用Promise.all来处理对API的多个请求,而不是使用for循环。

export default function Buttons({setOptionButtons, sendMessage, places}){

    const [data, setData] = useState(null)
    const [loading, setLoading] = useState(false)
    const [error, setError] = useState(null)
    const [names, setNames] = useState([])
    const [addresses, setAddresses] = useState([])

    const updateOptionButtons = () => {
        setOptionButtons(false);
      };

    const pressOption = async (input, option) => {
        const urlArray = []

        for(let i = 0; i < option.length; i++){
            urlArray.push(urls_with_option[i])
        }

        let requestsArray = urlArray.map((url) => {
            let request = new Request(url);
            return request;
        });
     

        await Promise.all(requestsArray.map((request) => {
            return fetch(request).then((response) => {
                return response.json();
            }).then((data) => {
                return data;
            });
        })).then((values) => {
            let items = values[0].result.items;
            let names = items.map((item) => item.name);
            let addresses = items.map((item) => item.address_name);
            setData(values)
            setNames((prevNames)=> [...prevNames, ...names])
            setAddresses((prevAdaress)=> [...prevAdaress, ...addresses])
        }).catch(console.error.bind(console));
        
        await sendMessage(input);
        updateOptionButtons()
    }

    return (
      //Html code here
    )
}

相关问题