Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs React钩子-处理异步api调用_Reactjs_React Hooks - Fatal编程技术网

Reactjs React钩子-处理异步api调用

Reactjs React钩子-处理异步api调用,reactjs,react-hooks,Reactjs,React Hooks,我正在尝试设置一个自定义钩子来处理项目中的所有api获取。我可以成功地拨打电话,并存储数据,但只能在第一次呼叫之后进行。我非常确信,由于竞争条件和异步的性质,第一个调用不会返回任何结果 这是我的钩子: import { useState, useEffect } from 'react' import api from 'services/api' const useHopServiceApi = () => { const [data, setData] = useState(

我正在尝试设置一个自定义钩子来处理项目中的所有api获取。我可以成功地拨打电话,并存储数据,但只能在第一次呼叫之后进行。我非常确信,由于竞争条件和异步的性质,第一个调用不会返回任何结果

这是我的钩子:

import { useState, useEffect } from 'react'
import api from 'services/api'

const useHopServiceApi = () => {
    const [data, setData] = useState([])
    const [url, setUrl] = useState('')
    const [body, setBody] = useState({})
    const [isLoading, setIsLoading] = useState(false)
    const [isError, setIsError] = useState(false)

    useEffect(() => {
        const fetchData = async () => {
            setIsError(false)
            setIsLoading(true)
            try {
                const result = await api.post(url, body)
                setData(result.d)
            } catch (error) {
                setIsError(true)
            }
            setIsLoading(false)
        }
        if (url && body) {
            fetchData()
        }
    }, [url, body])
    return [{ data, isLoading, isError }, setUrl, setBody]
}

export default useHopServiceApi
以及正在调用的组件:

const HomePage = (props) => {
  const [{ data, isLoading, isError }, doFetch, setBody] = useHopServiceApi()

const handleClickSelectInterests = () => {
    setBody({ count: 1 })
    doFetch('/GetPopularCities')
    console.log('data:', data)
  }
}

当我单击按钮(触发api调用)时,数据以空数组的形式注销,但在随后的单击中,它会被数据填充。

第一次单击后没有看到数据的原因是,在调用
doFetch
后,还没有立即从中获取数据

第二次单击按钮调用
handleClickSelectInterests
时,会记录数据,但它是来自第一次渲染的数据。可以很好地渲染更新后的数据,但不能在
handleClick
函数中记录最新的内容

下面是一个例子来说明我的意思:

根组件:

import React from "react";
import ReactDOM from "react-dom";

import useHopServiceApi from "./useHopServiceApi";
import "./styles.css";

function App() {
  const [{ data, isLoading, isError }, doFetch] = useHopServiceApi();
  console.log("Data in render!", data);
  const handleClick = () => {
    doFetch("/fakeUrl");
    // Data logged below will show the data from the previous request, not the latest
    console.log("Data in handle click!", data);
  };
  return (
    <div className="App">
      {isLoading && <div>Is loading!</div>}
      <button onClick={handleClick}>Simulate fetch!</button>
      {data && <div>Data! {data}</div>}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

上面的示例显示,您可以在渲染函数中使用最新的数据,即使您无法从以下位置将其记录到
handleClick
函数中:

setState函数用于更新状态。它接受一个新的状态值并使组件的重新呈现排队

在第一次单击时,钩子更新被调用,并且在执行状态更新之前到达console.log('data:',data),因此记录空数据

您应该将console.log放在函数的其他位置,以便更好地掌握执行顺序
import { useState, useEffect } from "react";
let numClick = 1;

const simulatedFetch = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`Fetch request data for request number ${numClick}`);
      numClick++;
    }, 2000);
  });
};
const useHopServiceApi = () => {
  const [data, setData] = useState([]);
  const [url, setUrl] = useState("");
  const [body, setBody] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsError(false);
      setIsLoading(true);
      try {
        const result = await simulatedFetch();
        console.log("new result!", result);
        setData(result);
        setUrl("");
      } catch (error) {
        setIsError(true);
      }
      setIsLoading(false);
    };
    if (url) {
      fetchData();
    }
  }, [url, body]);
  return [{ data, isLoading, isError }, setUrl, setBody];
};

export default useHopServiceApi;