【问题标题】:Define a function inside useEffect or outside?在 useEffect 内部或外部定义函数?
【发布时间】: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 }
}

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

【问题讨论】:

标签: javascript reactjs react-hooks next.js


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    1. 通过在使用效果之外定义函数,您要么需要禁用详尽的deps,否则会冒着意外获得陈旧函数的风险,或者需要使用回调使函数在每次渲染时都不更新
    2. 如果该函数仅用于 useEffect 中,则无需在每次渲染时重新创建该函数,因为这只是浪费循环
    3. 通过在 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 }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-07
      • 2020-08-19
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 2019-10-05
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多