【问题标题】:How do i properly use useEffect for a async fetch call with react? react-hooks/exhaustive-deps我如何正确使用 useEffect 进行异步获取调用和反应?反应钩子/详尽的deps
【发布时间】:2020-10-10 15:19:11
【问题描述】:

您好,我在 React 中遇到了 useEffect 钩子的问题。下面的代码可以正常工作,但 es-lint 建议我需要在 useEffect 的依赖项数组中提供依赖项。

// eslint-disable-next-line react-hooks/exhaustive-deps 的工作代码

export default function UsersList() {
   const [users, setUsers] = useState<User[]>([]);
   
   const { setError } = useContext(errorContext);
   const { isLoading, setIsLoading } = useContext(globalContext);
   
   useEffect(() => {
       if (users.length < 1) {
         fetchUsers();
       }
       // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);

     async function fetchUsers () {
       try {
         setIsLoading(true);
         const fetchedUsers = await api.getUsers();
         setUsers(fetchedUsers);
       } catch (error) {
         setError(error);
       } finally {
         setIsLoading(false);
       }
     }
}

无限循环代码

我试着这样写代码会触发一个无限循环..(因为状态在函数内部不断变化,并且由于声明的依赖关系而每次都会触发useEffect

 useEffect(() => {
    async function fetchUsers () {
      try {
        setIsLoading(true);
        const fetchedUsers = await api.getUsers();
        setUsers(fetchedUsers);
      } catch (error) {
        setError(error);
      } finally {
        setIsLoading(false);
      }
    }

    if (users.length < 1) {
      fetchUsers();
    }
  }, [setIsLoading, setError, users]);

我也尝试将 fetchUsers() 放在依赖项数组中,但这没有效果。

如何在组件挂载时正确设置异步调用而无需使用// eslint-disable-next-line react-hooks/exhaustive-deps

【问题讨论】:

    标签: javascript reactjs typescript react-hooks use-effect


    【解决方案1】:

    您的fetchUsers 函数正在通过每次渲染触发使用效果重新创建自己。您必须通过使用useCallback 包装它来保持其在渲染中的引用相同,请参阅https://reactjs.org/docs/hooks-reference.html#usecallback

    此外,为了确保我们只调用这个 useEffect 一次(当第一次渲染发生时),我们可以使用 useRef 来存储一个布尔值,这将防止 useEffect 无限循环

    export default function UsersList() {
      const [users, setUsers] = useState<User[]>([]);
      
      const { setError } = useContext(errorContext);
      const { isLoading, setIsLoading } = useContext(globalContext);
    
      const fetchUsers = useCallback(async function () {
        try {
          setIsLoading(true);
          const fetchedUsers = await api.getUsers();
          setUsers(fetchedUsers);
        } catch (error) {
          setError(error);
        } finally {
          setIsLoading(false);
        }
      }, [setIsLoading, setUsers, setError]);
    
      // Added a ref here to ensure that we call this function only once in initial render
      // If you need to refetch the users on error, just call fetchUsers
      const isFetchedRef = useRef(false);
      useEffect(() => {
        if (!isFetchedRef.current) {
          isFetchedRef.current = true;
          fetchUsers();
        }
      }, [isLoading, fetchUsers]);
    }
    

    【讨论】:

    • 感谢回复,有时间我会试试的!将其写为“工作代码示例”是否错误。如果是的话会有什么缺点?
    猜你喜欢
    • 2020-02-03
    • 2020-04-27
    • 1970-01-01
    • 2020-09-27
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    相关资源
    最近更新 更多