简体   繁体   中英

Useeffect dependency list warning from custom hook

So I'm building a react app and I'm trying to simplify calling my backend api with a custom hook using axios. This hook keeps loading and error state so that I don't have to keep that state in every component making a request. It also exposes a callApi() function which makes the actual requests which then changes the state in the hook. Here is the code for the custom hook.

import { useState } from 'react'
import axios, { AxiosRequestConfig } from 'axios'

export default <DataType>() => {
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')
  const [data, setData] = useState<DataType>()

  async function callApi(config: AxiosRequestConfig) {
    setLoading(true)
    setError('')
    try {
      const response = await axios.request<DataType>(config)
      setData(response.data)
    } catch (error) {
      if (error.response) setError(error.response.data.msg)
      else if (error.request) setError('A network error occured')
      else setError('An error occured')
    } finally {
      setLoading(false)
    }
  }

  return {
    data,
    loading,
    error,
    callApi
  }
}

I then try to use this callApi() method in a useEffect hook in a component where I want to make a request.

const { data: posts, loading, error, callApi } = useApi<Post[]>()

  useEffect(() => {
    callApi({
      url: 'http://localhost:4000/blog'
    })
  }, [])

This works as expected, but my the linter(set up with create-react-app) gives this warning:

React Hook useEffect has a missing dependency: 'callApi'. Either include it or remove the dependency array react-hooks/exhaustive-deps If I either add callApi to the dependency array or remove the dependency array altogether, an infinite loop will be created, since callApi updates the state, and I only want to call the api on mount.

If I remove the dependency list or add callApi to the dependency list, the effect will be called all the time in a infinite loop, and I just want to call on mount.

How should this warning be fixed, and is there any risk involved with the code(after all, the linter complains for a reason)?

Your useEffect use the callApi function returned by your custom hooks.

Since a function can change as any props or state in a component, React warns you that, if it will ever change, the new function will never be called.

If you want to get rid of the warning you should just add the function to the second argument array.

useEffect(() => {
    callApi({
      url: 'http://localhost:4000/blog'
    })
  }, [ callApi ])

This should work:

const callApi = useCallback(async (config: AxiosRequestConfig) => {
  setLoading(true)
  setError('')
  try {
    const response = await axios.request<DataType>(config)
    setData(response.data)
  } catch (error) {
    if (error.response) setError(error.response.data.msg)
    else if (error.request) setError('A network error occured')
    else setError('An error occured')
  } finally {
    setLoading(false)
  }
}), [])

... and...

useEffect(() => {
  callApi({
    url: 'http://localhost:4000/blog'
  })
}, [callApi])

The callApi never changes, so pass it to the useEffect will have the same behavior of useEffect(..., [])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM