自定义 React `useFetch` 钩子——我需要维护多个状态吗?

Custom React `useFetch` hook - do I need to maintain multiple states?

我已经实现了一个自定义 useFetch 挂钩,所以在我的应用程序中进行抓取:

import { useEffect, useState } from 'react'

const useFetch = ({ url, defaultData = null }) => {
  const [data, setData] = useState(defaultData)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(res => {
        setData(res)
        setLoading(false)
      })
      .catch(err => {
        setError(err)
        setLoading(false)
      })
  }, [])

  return [data, loading, error]
}

export default useFetch

然后我想到了...这将在整个应用程序中使用。它如何知道哪个 data/loading/error 属于哪个调用?当我第一次使用 useFetch,然后在应用程序的其他地方紧随其后进行另一个使用时,React 是否跟踪哪些内部状态变量属于钩子的哪个调用?

然后我想也许我需要沿着 Redux 路线做更多的事情,并在 useReducer 钩子的帮助下自己跟踪对自定义钩子的所有调用:

import { useEffect, useReducer } from 'react'

const reducer = (state, action) => {
  const { url, data, err } = action
  const currentState = state[url]

  switch (action.type) {
    case 'fetching':
      return { ...state, [url]: { ...currentState, loading: true } }
    case 'success':
      return { ...state, [url]: { ...currentState, loading: false, data } }
    case 'fail':
      return { ...state, [url]: { ...currentState, loading: false, err } }
    default:
      return state
  }
}

const useFetch = ({ url, defaultData = null }) => {
  const [state, dispatch] = useReducer(reducer, {}, { type: 'fetching', url })
  const { data: d, loading: l, err: e } = state[url]

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => dispatch({ type: 'success', url, data }))
      .catch(err => dispatch({ type: 'fail', err }))
  }, [])

  return [d || defaultData, l, e]
}

export default useFetch

我是否需要像第二个示例那样手动跟踪对 useFetch 的所有调用?或者 React 是否在其内部处理这个问题,而第一个示例就是我所需要的?

每个自定义挂钩都有自己的状态,不会在同一挂钩的不同实例之间共享状态。因此你不需要跟踪哪个状态属于哪个钩子。

Hooks 只会在不同实例之间共享逻辑而不共享数据,很像 HOCs and Render Props

所以第一个例子就可以正常工作了。

在你的情况下,对 useFetch 的多次调用本质上会导致对 useStateReact FAQs 的多次调用,用 useState 解释了状态的独立性,这确实回答了你的问题疑问

React keeps track of the currently rendering component. Thanks to the Rules of Hooks, we know that Hooks are only called from React components (or custom Hooks — which are also only called from React components).

There is an internal list of “memory cells” associated with each component. They’re just JavaScript objects where we can put some data. When you call a Hook like useState(), it reads the current cell (or initializes it during the first render), and then moves the pointer to the next one. This is how multiple useState() calls each get independent local state.

我写了一个很好的例子,说明你可以做些什么来获得更健壮的 useFetch hook in my package use-http