无法处理 POST 请求 + StrictMode

Can't deal with POST request + StrictMode

提问人:Cassiano Matos 提问时间:8/1/2023 最后编辑:tadmanCassiano Matos 更新时间:8/1/2023 访问量:150

问:

我只需要在进入页面时运行一次请求,目的是验证用户,根据响应,页面上会显示不同的内容。POST

我用来做请求,下面是例子:react-query

const { mutate } = useMutation({
  mutationFn: () => axios.post('/api/validate-users').then(res => res.data),
});

useEffect(() => {
  mutate({}, {
    onSuccess: (data) => {
      // Do something based on response data
    }
  })
}, [])

它在没有 StrictMode 的情况下正常工作,但是当它进入时,它会使 API 被调用两次,在我的用例中,我不能有这种行为。我在 React 的文档中读到了它,但是我不能将此验证附加到按钮上,例如,每次进入页面时都需要它运行。

如何使用 StrictMode 仅调用一次此 API?

我尝试使用 ,以防止 API 被调用两次。它奏效了,但这是一个很大的解决方法,我觉得有一些更容易的事情要做。React Refs

我知道在生产环境中这应该不是问题

reactjs react-hooks react-query 严格模式 tanstackreact-query

评论

0赞 Chad S. 8/1/2023
你在这里反对框架..您不应该在生命周期事件上触发突变。您应该触发突变以响应用户操作。

答:

0赞 Mohammad Akram 8/1/2023 #1

你在 API 被调用两次时遇到的行为与 React 的严格模式和开发过程中的双重渲染有关。

React 的严格模式有意触发组件的两次渲染,以帮助检测应用程序中的潜在问题。这可能会导致一些副作用的问题,例如在您的情况下进行两次 API 调用。额外的渲染旨在捕捉意外的副作用,并帮助开发人员在开发过程中识别和修复问题。

若要仅进行一次 API 调用,可以使用以下方法:

将 useEffect 钩子包装在 useLayoutEffect 钩子中。 在所有 DOM 突变之后,但在浏览器绘制之前同步运行。这样,可以确保效果在渲染到屏幕之前运行。useLayoutEffect

为了避免 React 的严格模式导致的第二次渲染,请使用 ref 来跟踪 API 调用是否已经进行。

import { useState, useEffect, useLayoutEffect, useRef } from 'react';
import { useMutation } from 'react-query';
import axios from 'axios';

function MyComponent() {
  const [isAPICalled, setAPICalled] = useState(false);
  const isAPICalledRef = useRef(false); // Ref to track whether the API call has been made

  const { mutate } = useMutation({
    mutationFn: () => axios.post('/api/validate-users').then((res) => res.data),
  });

  // useLayoutEffect will run before the render (synchronously)
  useLayoutEffect(() => {
    if (!isAPICalledRef.current) {
      mutate({}, {
        onSuccess: (data) => {
          // Do something based on response data
        },
      });

      isAPICalledRef.current = true; // Mark the API call as made in the ref
      setAPICalled(true); // Update the state to trigger a render (optional)
    }
  }, [mutate]);

  // Render based on the API response and other logic
  return <div>{/* Your component content */}</div>;
}

export default MyComponent;

评论

0赞 Cassiano Matos 8/1/2023
这是我发现的解决方法之一,它将触发 API 一次。但这并不理想,如果我使用 Refs,突变回调(即:)将不会触发,因为组件在突变完成之前卸载。(TanStack 博客)我想知道是否有办法防止这种情况发生onSuccessuseEffect