在useEffect或外部定义函数?

问题描述 投票:1回答:2

为什么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
2个回答
0
投票

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

  1. 通过在使用效果之外定义函数,您要么需要禁用穷举并且可能会意外拥有过时的函数,要么需要使用Callback使该函数在每次渲染时都不更新
  2. 如果该函数仅在useEffect中使用,则无需在每个渲染器上重新创建该函数,因为这只是浪费的周期
  3. 通过在useEffect中定义它,可以更轻松地对异步函数进行清理,因为您可以定义可以在效果中进行修改的变量。]​​>
  4. 例如,在最后一个上,您可以执行一些操作以防止在效果清除时调用状态。

您还可以将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 }
}

0
投票

技术上,fetchData应该是根据React Hooks规则对useEffect的依赖项。但是,如果添加了它,它将给您一个错误,说明如果在组件内部定义了此钩子,则在重新创建函数时,它将导致useEffect在每次重新渲染时运行。

© www.soinside.com 2019 - 2024. All rights reserved.