Exploring Conditional Execution of React Hooks
Discover how to conditionally execute React Hooks for more flexible functionality in your React applications#react#hooks#componentsOctober 3 · 3 min read
React hooks can't be called conditionally (see the rules of hooks). Except for the use()
hook, which is experimental unless you're using Next.js 13. However, we can work around this in two different ways:
Component approach
React is all about components, and hooks get executed inside components. We can conditionally render components. Put your hook inside a component and call it a day.
function Parent() {
const [shouldExecuteHook, setShouldExecuteHook] = useState(false)
return (
<>
{shouldExecuteHook ? <ChildHook /> : null}
<button onClick={() => setShouldExecuteHook(current => !current)}>
Toggle
</button>
</>
);
}
function ChildHook() {
useEffect(() => {
console.log('The hook is mounted!');
return () => {
console.log('The hook is unmounted!');
}
}, [])
return null;
}
This is useful when you don't have control over the hook's implementation or don't want to update it to support a disabled/enabled flag.
Disabled/Enabled flag
If we have control over the implementation of the hook, you could add a disabled
or enabled
flag to its input API, which we can use to control what happens when it executes.
Note that this example doesn't prevent the hook and the hooks used in its implementation from running. As you can see in the following example, what we do to prevent the hook from doing what it's supposed to do is check the flag and return early if the hook is disabled. That's because the useEffect
hook will still run.
function useMyHook(disabled: boolean) {
useEffect(() => {
if (disabled) {
return;
}
console.log('The hook is mounted!');
return () => {
console.log('The hook is unmounted!');
}
}, [enabled])
}
function Parent() {
const [shouldExecuteHook, setShouldExecuteHook] = useState(false)
useMyHook(shouldExecuteHook)
return (
<button onClick={() => setShouldExecuteHook(current => !current)}>
Toggle
</button>
);
}
Which one to pick?
Honestly, the experience will tell you because each hook is a different world. Maybe the following section with questions and answers helps you pick what you need:
Questions and answers
Is this hook returning a value needed in the component where it's used?
Flag approach. Here's an example from the famous react-query
library.
I have a hook from an external library, which I want to call conditionally. The hook is used to trigger a side effect.
Component approach. Here's a quick example use case for analytics.
// External hook, will hook into React Router's location state and send events to Google Analytics
useRouterAnalytics()
// In our app, if our users don't consent to tracking, we can wrap this in a component
function RouterAnalytics() {
useRouterAnalytics();
return null;
}
// Then, we can conditionally use it on our app:
function AppComponent() {
const enableTracking = ... get this from somewhere idk ...
return (
<>
{enableTracking ? <RouterAnalytics /> : null}
<OtherComponents />
</>
)
}
I followed the Component approach, but now I need to reset the state of the hook; what do I do?
key
to the rescue, we're working with a React Component; we can use the key
prop to reset its state.
function ConsoleLogCount() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount(current => current + 1)
}, 1000);
return () => {
clearInterval(interval);
}
}, []);
useEffect(() => {
console.log(count);
}, [count]);
return null;
}
function AppComponent() {
const enableCount = ... get this from somewhere idk ...
const [resetCountKey, setResetCountKey] = useState(0)
return (
<>
{enableCount ? <ConsoleLogCount key={resetCountKey} /> : null}
<button onClick={() => setResetCountKey(key => key + 1)}>
Reset count
</button>
<OtherComponents />
</>
)
}
Hope you liked the article! If you have more questions, feel free to reach out on social media or email :)