简体   繁体   English

React.js 自定义获取挂钩中的错误

[英]Bug in React.js custom fetch hook

I have the following custom hook, useFetch , in my React (v18.1.0) project to fetch data from a Node.js server.我的 React (v18.1.0) 项目中有以下自定义挂钩useFetch ,用于从 Node.js 服务器获取数据。

export default function useFetch(url, requestType, headers, body) {
  const [error, setError] = useState(false);
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  console.log('Inside useFetch hook');
  useEffect(() => {
    console.log('Inside useEffect in the useFetch hook');
    const controller = new AbortController();
    async function retrieveData(reqUrl) {
      try {
        console.log('Inside the useFetch try block');
        const res = await fetchData(
          reqUrl,
          requestType,
          headers,
          body,
          controller.signal
        );
        console.log('Done with fetch; this is the server response ', res);
        setData(res);
        setLoading(false);
        console.log('Done with useFetch try block.');
      } catch (err) {
        if (err.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(true);
          setData(err);
          setLoading(false);
        }
      }
    }
    retrieveData(url);
    return () => {
      controller.abort();
    };
  }, []);
  return { loading, error, data };
}

My useFetch hook uses a function called fetchData to send a fetch request to the server.我的 useFetch 挂钩使用名为fetchData的 function 向服务器发送提取请求。

async function fetchData(url, requestType, headers, payload, abortSignal) {
  console.log('Inside the fetch function');
  let res = await fetch(url, {
    method: requestType,
    headers: headers,
    body: payload,
    signal: abortSignal ? abortSignal : null,
  });
  if (res.ok) {
    const resJson = await res.json();
    console.log('Returning value from fetch function');
    return { status: res.status, response: resJson };
  } else {
    await fetchErrorHandler(res);
  }
}

The useFetch hook is invoked once in my VideoPlayer component. useFetch挂钩在我的VideoPlayer组件中被调用一次。

function VideoPlayer() {
  const { videoId } = useParams();
  const url = `http://localhost:5000/videos/${videoId}`;
  const { loading, error, data } = useFetch(url, 'GET', {}, null);

  return (
    <div>
      {loading && <div />}
      {!loading && error && <h2>{data.message}</h2>}
      {!loading && !error && (
        <video width={600} height={450} controls src={data.response.videoUrl}>
          Cannot display video player.
        </video>
      )}
    </div>
  );
}

The problem I'm facing is that when the VideoPlayer component is mounted to the DOM and useFetch is called, the execution flow looks like this: Execution flow of useFetch hook .我面临的问题是,当VideoPlayer组件挂载到 DOM 并useFetch时,执行流程如下所示: Execution flow of useFetch hook As is seen in the image, everything seems fine until the line Inside the fetch function is printed in the console.如图所示,在控制台打印Inside the fetch function行之前,一切似乎都很好。 After this, the useEffect hook within the useFetch is called again, for reasons I'm unable to understand (my dependency array is empty and, moreover, there's no state change at this point).此后,再次调用useFetch中的useEffect挂钩,原因我无法理解(我的依赖项数组为空,而且此时没有 state 更改)。 Then, it tries to execute the fetch another time, aborts it, and then eventually returns a response, presumably to the original fetch request.然后,它尝试再次执行fetch ,中止它,然后最终返回一个响应,大概是对原始fetch请求的响应。 At the end of this process, useFetch is called yet again.在此过程结束时,将再次调用useFetch If anyone can help me shed some light on why the hook is behaving this way, instead of simply executing the fetch request once and returning the response, I will greatly appreciate it.如果有人能帮助我阐明为什么挂钩会以这种方式运行,而不是简单地执行一次fetch请求并返回响应,我将不胜感激。

I assume you use React in StrictMode - this is the default for apps created with create-react-app.我假设您在StrictMode中使用 React - 这是使用 create-react-app 创建的应用程序的默认设置。

In strict mode, effects can fire twice while in development mode.在严格模式下,效果可以在开发模式下触发两次 You can verify that this causes your problem by running a production build.您可以通过运行生产构建来验证这是否会导致您的问题。 If the problem goes away, it is likely caused by StrictMode.如果问题消失,则可能是由 StrictMode 引起的。

My suggestion is to not change anything - actually, your code seems to work fine: the first effect execution triggers a fetch, then the second effect execution aborts the initial fetch and fetches for a second time.我的建议是不要更改任何东西——实际上,您的代码似乎工作正常:第一个效果执行触发一次提取,然后第二个效果执行中止初始提取并进行第二次提取。 This is exactly, what the code is expected to do.这正是代码预期执行的操作。

You can use axios to deal with API可以用axios来处理API

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM