reactjs - 使用异步获取函数对无限循环的 useEffect

标签 reactjs react-hooks

我试图理解为什么以下 useEffect 在无限循环中运行。我创建了 fetchSchedule 辅助函数来调用 getSchedule 服务(使用 Axios 查询 API 端点)。我没有在 useEffect Hook 中定义此函数的原因是,我想在调用 onStatus 函数时也调用它(这会在单独的端点上切换 bool PUT 请求)。

eslinter 要求将 fetchSchedule 添加到依赖项数组中,这似乎触发了无限循环。

它应该工作的方式是在第一次渲染时从数据库中获取数据,然后仅在每次更新 value 属性或切换 onStatus 按钮时获取数据.

到目前为止,我的研究似乎表明这可能与 useEffect 与异步函数和闭包的行为方式有关。我仍在尝试理解 Hooks,显然我的代码中有些东西没有得到......

import React, { useEffect, useCallback } from 'react';
import useStateRef from 'react-usestateref';
import { NavLink } from 'react-router-dom';
import { getSchedule, updateStatus } from '../../services/scheduleService';
import Status from './status';
// import Pagination from './pagination';

const List = ({ value }) => {
  // eslint-disable-next-line
  const [schedule, setSchedule, ref] = useStateRef([]);
  // const [schedule, setSchedule] = useState([]);

  const fetchSchedule = useCallback(async () => {
    const { data } = await getSchedule(value);
    setSchedule(data);
  }, [value, setSchedule]);

  const onStatus = (id) => {
    updateStatus(id);
    fetchSchedule();
    console.log('fetch', ref.current[0].completed);
  };

  useEffect(() => {
    fetchSchedule();
  }, [fetchSchedule]);
return (...)

最佳答案

2021 年 3 月更新

react-usestateref 的存储库所有者合作后,该软件包现在可以按照最初的预期运行,并且可以安全地用作 useState 自版本 的替代品>1.0.5。当前的实现如下所示:

function useStateRef(defaultValue) {
  var [state, setState] = React.useState(defaultValue);
  var ref = React.useRef(state);

  var dispatch = React.useCallback(function(val) {
    ref.current = typeof val === "function" ?
    val(ref.current) : val;

    setState(ref.current);
  }, []);

  return [state, dispatch, ref];
};

如果没有这个react-usestateref导入,你会没事的。

该钩子(Hook)返回一个用于设置状态的普通匿名函数,这意味着它将在每次渲染时重新创建 - 您不能将其有效地包含在任何依赖项数组中,因为它也会在每次渲染时更新。但是,由于该函数是从未知的自定义 Hook 返回的(并且无论如何,ESLint 都会正确识别它不是正确的 setter 函数),因此当您不这样做时,您会收到警告。

它试图解决的“问题”也会在您的代码中引入不良实践 - 这是避免正确处理依赖项的好方法,这些依赖项可以使您的代码更安全。

如果你回到标准状态 Hook ,我相信这段代码会正常工作。不要尝试在 onStatus 中获取状态的引用,而是使其异步并从 fetchSchedule 返回数据并设置它。

const [schedule, setSchedule] = useState([]);

const fetchSchedule = useCallback(async () => {
  const { data } = await getSchedule(value);
  setSchedule(data);
  return data;
}, [value]);

const onStatus = async (id) => {
  updateStatus(id);
  const data = await fetchSchedule();
};

useEffect(() => {
  fetchSchedule();
}, [fetchSchedule]);

或者,虽然我再次不建议使用它,但我们实际上可以编写一个安全版本的 useStateRef 钩子(Hook):

function useStateRef(defaultValue) {
    var [state, setState] = React.useState(defaultValue);

    var ref = React.useRef(defaultValue);
    ref.current = state; 

    return [state, setState, ref];
}

状态设置函数在组件的整个生命周期中始终引用相同,因此可以将其包含在依赖项数组中,而不会导致重新创建效果/回调。

关于reactjs - 使用异步获取函数对无限循环的 useEffect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65782076/

相关文章:

react-native - 内置的 react 原生组件是纯的吗?

javascript - Kuzzle getUser 通过 JWT Token 提前生成

reactjs - 如何在 React Router v4 中嵌套路由?

javascript - 不同组件中的提交按钮会造成可访问性问题

javascript - useAnimationOnDidUpdate react 钩子(Hook)实现

reactjs - 如果功能组件的 URL 已更改,则取消刷新

javascript - 即使某些图像存在,也不会在 react 应用程序中加载

javascript - 在reactjs中使用setInterval函数的正确位置是什么

reactjs - 是否可以在不使用 JSX 的情况下使用 React Hooks API(在 typescript 中)

javascript - 在组件的单​​独文件中使用 React hook