The context
A colleague of mine helped identify a pattern that has helped avoid using hooks for setting default values.
If you ever found yourself needing to write useSetDefaultSomething(), this article is for you.
The goal
When a customer opens mysite.com/?myParam=foo, I want to load the correct FooComponent. However, if mysite.com is opened with no param is set, I want it to default to FooComponent as well.
In the following component, a hook is used to set some sort of default parameter:
export const MyMainComponent = () => {
useSetDefaultParameters();
const { params } = useMyContext();
return (
<div className="...">
{params.myParam === "foo" && <FooComponent />}
{params.myParam === "bar" && <BarComponent />}
....
The hook itself monitors the url params for changes and updates a context whenever myParam changes.
export const useSetDefaultParameters = () => {
const { myParam } = useGetQueryParam();
const { setParam } = useMyContext();
useEffect(() => {
setParam("myParam", defaults["myParam"]);
}, [myParam]);
};
The problems
- UI flicker: since
useEffectruns after every render, the UI will initially paint a state whereurlParamis undefined before it receives the default value. -
useSetDefaultParametersis a brittle side-effect: as the app gets built out, there may be different reasons for why we wanturlParamto change without affecting the originalMyMainComponent.
The solution
Instead of writing your app in a way that requires side-effects, a better option is:
- Put what you need into a hook, eg
useGetMyParam. - Make the hook return a default value if
urlParamis undefined.
export const useGetMyParam = () => {
const { myParam } = useGetQueryParam();
return myParam || defaults["myParam"]
}
Then, our main component can be updated to:
export const MyMainComponent = () => {
const { myParam } = useGetMyParam();
return (
<div className="...">
{myParam === "foo" && <FooComponent />}
{myParam === "bar" && <BarComponent />}
....
With this, we get rid of the useEffect and our UI renders the correct component from the first time π
Top comments (0)