Jason Lam
Jason Lam

Reputation: 1392

React hooks - How to call useEffect on demand?

I am rewriting a CRUD table with React hooks. The custom hook useDataApi below is for fetching data of the table, watching the url change - so it'll be triggered when params change. But I also need to fetch the freshest data after delete and edit. How can I do that?

const useDataApi = (initialUrl, initialData) => {
  const [url, setUrl] = useState(initialUrl)

  const [state, dispatch] = useReducer(dataFetchReducer, { data: initialData, loading: true })

  useEffect(() => {
    const fetchData = async () => {
      dispatch({ type: 'FETCH_INIT' })
      const result = await instance.get(url)
      dispatch({ type: 'FETCH_SUCCESS', payload: result.data })
    }

    fetchData()
  }, [url])

  const doFetch = url => {
    setUrl(url)
  }

  return { ...state, doFetch }
}

Since the url stays the same after delete/edit, it won't be triggered. I guess I can have an incremental flag, and let the useEffect monitor it as well. But it might not be the best practice? Is there a better way?

Upvotes: 4

Views: 7422

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281626

All you need to do is to take the fetchData method out of useEffect and call it when you need it. Also make sure you pass the function as param in dependency array.

const useDataApi = (initialUrl, initialData) => {
  const [url, setUrl] = useState(initialUrl)

  const [state, dispatch] = useReducer(dataFetchReducer, { data: initialData, loading: true })

  const fetchData = useCallback(async () => {
      dispatch({ type: 'FETCH_INIT' })
      const result = await instance.get(url)
      dispatch({ type: 'FETCH_SUCCESS', payload: result.data })
  }, [url]);

  useEffect(() => {
    fetchData()
  }, [url, fetchData]); // Pass fetchData as param to dependency array

  const doFetch = url => {
    setUrl(url)
  }

  return { ...state, doFetch, fetchData }
}

Upvotes: 9

Related Questions