bunny
bunny

Reputation: 2027

Use custom hook in callback function

I have a customHook, and I need to call it in two places. One is in the top level of the component. The other place is in a onclick function of a button, this button is a refresh button which calls the customHook to fetch new data like below. I am thinking of two approaches:

  1. create a state for the data, call hook and set the data state in the component and in the onclick function, call hook and set the data state. However, the hook cannot be called inside another function i.e onclick in this case.

  2. create a boolean state called trigger, everytime onclick of the button, toggle the trigger state and pass the trigger state into the myCallback in the dependent list so that myCallback function gets recreated, and the hook gets called. However, I don't really need to use this trigger state inside the callback function, and the hook gives me error of removing unnecessary dependency. I really like this idea, but is there a way to overcome this issue?

  3. Or is there any other approaches to achieve the goal?

    const MyComponent = () => {  
         const myCallback = React.useCallback(() => { /*some post processing of the data*/ }, []);  
         const data = customHook(myCallback);  
    
         return <SomeComponent data={data}>
                     <button onclick={/*???*/}></button>
                 </SomeComponent>; 
     };
    

Upvotes: 2

Views: 1381

Answers (1)

Scotty Jamison
Scotty Jamison

Reputation: 13129

It is possible to make your second example work with some tweaking. Instead of passing in a dependency to update the effect function, just make the effect function a stand-alone function that you pass into useEffect, but can also call in other places (e.g. you can return the effect function from your hook so your hook users can use it too)

For example:

const App = () => {
  const { resource, refreshResource } = useResource()
  return (
    <div>
      <button onClick={refreshResource}>Refresh</button>
      {resource || 'Loading...'}
    </div>
  )
}

const useResource = () => {
  const [resource, setResource] = useState(null)
  const refreshResource = async () => {
    setResource(null)
    setResource(await fetchResource())
  }
  useEffect(refreshResource, [])
  return { resource, refreshResource }
}

const fetchResource = async () => {
  await new Promise(resolve => setTimeout(resolve, 500))
  return Math.random()
}

Edit

I hadn't realized that the hook couldn't be edited. I honestly can't think of any good solutions to your problem - maybe one doesn't exist. Ideally, the API providing this custom hook would also provide some lower-level bindings that you could use to get around this issue.

If worst comes to worst and you have to proceed with some hackish solution, your solution #2 of updating the callback should work (assuming the custom hook refetches the resource whenever the parameter changes). You just have to get around the linting rule, which, I'm pretty sure you can do with an /* eslint-disable-line */ comment on the line causing the issue, if eslint is being used. Worst comes to worst, you can make a noop function () => {} that you call with your trigger parameter - that should put the linter at bay.

Upvotes: 1

Related Questions