在 useEffect 内部还是外部定义一个函数?

Adr*_*ien 6 javascript reactjs next.js react-hooks

为什么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 }
}
Run Code Online (Sandbox Code Playgroud)

我会这样做:

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 }
}
Run Code Online (Sandbox Code Playgroud)

它似乎更容易阅读和更好地组织。我在想这可能是一种反模式还是其他什么?

Zac*_*ber 6

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

  1. 通过在 use 效果之外定义函数,您要么需要禁用详尽的 deps 并冒着意外拥有过时函数的风险,要么需要 useCallback 使函数不会在每次渲染时更新
  2. 如果该函数仅在 useEffect 中使用,则无需在每次渲染时重新创建该函数,因为这只是浪费周期
  3. 通过在 useEffect 中定义异步函数,可以更轻松地处理异步函数的清理工作,因为您可以定义能够在效果中修改的变量。

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

您还可以将 AbortController 与 fetch 结合使用来取消 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 }
}
Run Code Online (Sandbox Code Playgroud)