【问题标题】:Strange behaviour with useEffectuseEffect 的奇怪行为
【发布时间】:2019-12-30 17:13:30
【问题描述】:

我正在使用反应钩子构建一个项目。我的useEffect 函数如下所示...

useEffect(() => {
  (async function() {
    const queryParams = await qs.parse(props.location.search, { ignoreQueryPrefix: true }).code;
    if (queryParams != undefined) {
      setCode(queryParams);
      postLogin();
    }
  })();
});

postLogin 函数只是使用上面定义的查询参数向服务器发出的GET 请求。看起来是这样的……

const postLogin = async () => {
  await axios.get("http://XXX.XXX.X.XX:52805/user/auth", {
    params: {
      auth_code: code
    }
  }).then(result => {
    setAuthTokens(result.data.credentials.access_token);
    setLoggedIn(true);
  }).catch(e => {
    setIsError(true);
  });
}

发生的情况是,当我只希望它被调用一次时,该请求将被多次调用。

正如您在上面的屏幕截图中看到的,在 5 个请求中,一个成功,另一个失败,我不确定是什么原因造成的。任何想法都会有所帮助。

【问题讨论】:

    标签: javascript reactjs axios react-hooks


    【解决方案1】:

    您可能需要添加一个空数组 ([]) 作为钩子的第二个参数。它会阻止钩子多次运行。

    数组应该包含变量(通常是组件状态的一部分),如果它们发生变化,钩子应该监视并重新运行。 无论钩子做什么,变量都应该是至关重要的。

    假设您的钩子应该显示某个 类别 的 youtube 频道的订阅者数量 - 假设类别是 A、B 和 C(假设),用户可以在其中切换要查看的类别可能正在使用下拉列表;那么数组将包含 category 变量,这样每当它发生变化时,挂钩就会运行以获取该类别中的订阅者数量。让数组为空是一种告诉 React 你没有依赖项并且你可以接受钩子第一次运行时所做的事情的一种方式。

    React 比较该数组中的值以了解每次渲染的变化,如果它们没有变化,则跳过钩子。如果你把它留空,那么任何值都不会改变,这意味着钩子将运行一次,然后在随后的重新渲染中被跳过。

    【讨论】:

    • 您可能会解释为什么,即数组参数的用途。
    • 一个空参数解决了这个问题。由于我的useEffect 函数依赖于queryParams 变量,看来我必须在第二个参数中添加它。
    • @Bolboa queryParams 仅在该效果回调的范围内首先定义,因此它不是依赖项。但是,如果 setCode 是状态变量的设置器,您可能需要包含 code(或您所称的状态变量)。
    【解决方案2】:

    您的 useEffect 挂钩在每次渲染时运行。由于您在请求完成后调用setIsErrorsetLoggedIn,这将触发另一个渲染和另一个渲染等。老实说,我很惊讶没有无限循环。要解决此问题,请尝试使其仅在之前未尝试过的情况下尝试登录(没有出现错误且当前未登录。)像这样:

    useEffect(async () => {
      if (isLoggedIn || isError) return; // Don't try again if a request has already succeeded or failed.
      // Optionally use "isLoggedIn || isError || isLoading" to prevent multiple concurrent requests,
      // which may cause further re-rendering.
      const queryParams = await qs.parse(props.location.search, { ignoreQueryPrefix: true }).code;
      if (queryParams != undefined) {
        setCode(queryParams);
        postLogin();
      }
    });
    

    如果你确定你只希望它运行一次(在第一次渲染时)给它一个空的依赖数组,这样它就不会再运行了。

    【讨论】:

    • useEffect 钩子不能有异步函数作为回调。它必须像 OP 一样同步并声明异步函数。
    猜你喜欢
    • 2019-08-12
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 2021-06-08
    • 2015-07-20
    相关资源
    最近更新 更多