I have two custom React hooks that fetch different data and parse it. Both hooks return an object of the same type. I have a component that displays that data and depending on a "variant" prop, i want it to decide which of those two hooks it mounts.
Example code:
const useJohn = () => {
// fetch & parse some data
return { parsedData: { date: new Date(), name: 'John Doe' } }
}
const useJane = () => {
// fetch & parse some data
return { parsedData: { date: new Date(), name: 'Jane Smith' } }
}
const dataDisplay = ({ variant }: { variant: 'John' | 'Jane' }) => {
const hook = variant === 'John' ? useJohn : useJane
const { parsedData } = hook()
return <div>{`${parsedData.date.toString()} ${parsedData.name}`}</div>
}
I get no warnings/errors from this pattern and everything seems to be working fine. Is this a legitimate way of conditionally using custom hooks? Or are there any issues with this pattern that i am not aware of?
2
Answers
Ok, first, we’ll suppose that both useJohn and useJane are calling some effects herein.
And if they do, doing:
is wrong, and will fail!
If it did not fail yet, it’s because you did not update the prop of your component. But as soon as the prop changes, the hook being called will change, and you will break a react invariant which is that a component should render the exact same number of hook calls at each render.
i.e., this will fail:
How should you fix that?
Either you create a high order component that handles the John vs Jane decision, so that you have two components: one that does useJohn and the other that always does useJane, and use the same display component:
Another, maybe simpler way, would be to create a single effect:
Which is best really depends on context that’s not shared in your question, and that choice is up to you.
If you want conditionally use a hook, use the condition in its implementation.
Please check the accepted post here use the condition in its implementation.
Please see below your code refactored on the same basis. The test run results have also been enclosed.
App.js
Test run: Browser displays – on load and after 5 seconds