在 useEffect 内部或外部定义函数?

Posted

技术标签:

【中文标题】在 useEffect 内部或外部定义函数?【英文标题】:Define a function inside useEffect or outside? 【发布时间】:2020-08-15 01:53:12 【问题描述】:

为什么fetchData 函数定义在useEffect 内部而不是外部?

链接: https://github.com/zeit/next.js/blob/canary/examples/with-graphql-faunadb/lib/useFetch.js

import  useState, useEffect  from 'react'

export default function useFetch(url, options) 
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)

  useEffect(() => 
    const fetchData = async () => 
      try 
        const res = await fetch(url, options)
        const json = await res.json()

        setData(json)
       catch (error) 
        setError(error)
      
    
    fetchData()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , [url])

  return  data, error 

我会这样做的:

import  useState, useEffect  from 'react'

export default function useFetch(url, options) 
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)

  // Defined outside of useEffect
  // `u` instead of `url` for not overlapping
  // with the one passed in useFetch()
  const fetchData = async (u) => 
    try 
      const res = await fetch(u, options)
      const json = await res.json()

      setData(json)
     catch (error) 
      setError(error)
    
  

  useEffect(() => 
    // Using url as an argument
    fetchData(url)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , [url])

  return  data, error 

它似乎更易于阅读且更有条理。我在想这可能是一种反模式或其他什么?

【问题讨论】:

我在 React 文档中找到了我的答案:fr.reactjs.org/docs/… 【参考方案1】:

根据 React Hooks 规则,从技术上讲 fetchData 应该是 useEffect 的依赖项。但是如果你添加它,它会给你一个错误,说它会导致 useEffect 在每次重新渲染时运行,因为如果这个钩子是在组件中定义的,则重新创建函数。

但是由于它是在组件之外定义的,所以我的理解是不会重新创建该函数。然后只需将 fetchData 添加为依赖项。

如果这个 useEffect 在组件中使用,您可以只在 useEffect 中传递函数,或者添加依赖项并使用 useCallback 覆盖您的 fetchData。

【讨论】:

【参考方案2】:

我通常在 useEffect 中定义函数,有几个原因

    通过在使用效果之外定义函数,您要么需要禁用详尽的deps,否则会冒着意外获得陈旧函数的风险,或者需要使用回调使函数在每次渲染时都不更新 如果该函数仅用于 useEffect 中,则无需在每次渲染时重新创建该函数,因为这只是浪费循环 通过在 useEffect 中定义异步函数,可以更轻松地对异步函数进行清理,因为您可以定义能够在效果中修改的变量。

例如,在最后一个上,您可以执行一些操作来防止在清理效果时调用状态。

您也可以使用带有 fetch 的 AbortController 来取消 fetch。

import  useState, useEffect  from 'react'

export default function useFetch(url, options) 
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)

  useEffect(() => 
    let isUnmounted = false;
    const fetchData = async () => 
      try 
        const res = await fetch(url, options)
        const json = await res.json()
        if(!isUnmounted) setData(json)
       catch (error) 
        if(!isUnmounted) setError(error)
      
    
    fetchData()
    return ()=>isUnmounted = true;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , [url])

  return  data, error 

【讨论】:

以上是关于在 useEffect 内部或外部定义函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 useEffect 之外的函数被调用,而没有依赖数组的 useEffect 内部的函数却没有?

安装jmeter 环境变量都配置好了 可还是出现不是内部外部命令

无效的挂钩调用。钩子只能在反应函数组件内部使用...... useEffect,redux

react ESlint警告: React Hook useEffect has a missing dependency

PHP闭包函数

PHP闭包函数