JavaScript can only return one value from a function. However, destructuring in modern JavaScript makes this largely irrelevant.
We can return multiple values in arrays or objects from a function and instantly destructure them. And, as you know, a React hook is just a convention-following function.
const [one, two] = useNumbers()
const { a, b, c } = useAlphabet()
So why use one method over another?
Let's look at some different use cases and explore why we might want to return an array vs. an object.
First, it should be noted, that we don't have to return anything. The built in React.useEffect
hook does just this, (returning undefined
actually).
We can also just return a single value, such as a string or integer. An example of this might be a hook that subscribes to a WebSocket API and returns a continuously updating value representing the current number of users online:
function OnlineUsers() {
const userCount = useOnlineUserCount()
return (
<Users count={userCount} />
)
}
Returning an Array
A hook that has a very general use case benefits from exporting return values as an array. A great example of this is actually the built-in React.useState
hook. Exporting an array makes it easy to customize the names of the state variables and their setters. Unique names enable us to use the hook repeatedly.
const [color, setColor] = useState('MintCream')
const [width, setWidth] = useState('100vw')
A slightly-contrived example of a custom hook that would benefit from returning an array might be CSS builder that also holds on to some state.
const [leftStyle, setLeftTheme] = useStyleBuilder('dank-kitty')
const [rightStyle, setRightTheme] = useStyleBuilder('no-drama-llama')
When to Return an Array
The number of values that need to be returned is low. Order is significant and remembering the order of a bunch of values takes extra brain cycles.
The hook is expected to be used more than once in the same component. Although we can rename properties when destructuring an object, the simpler syntax for custom-named values returned from an array makes more sense.
Returning an Object
A hook that has a more specialized use case and returns a larger number of values may benefit by returning an object.
Object destructuring doesn't rely on ordering and it is easier to ignore values that are not needed. An example might be a hook with 3 or 4 state values along with handler functions:
const { color, count, isValid, handleChangeColor, handleChangeCount } = useItemOptions()
When to Return an Object
The number of values that need to be returned is high. We don't have to remember the order or even use all the values when returning an object.
The hook is not expected to be used more than once in the same component. We can use the original property names when destructuring an object returned from a hook that will only be used once in a component.
Not destructuring
If a hook needs to return a larger number of values AND is expected to be used more than once, we don't have to destructure at all. This can occasionally be useful.
const leftOptions = useItemOptions()
const rightOptions = useItemOptions()
return (
<>
<Column
side="left"
color={leftOptions.color}
count={leftOptions.count}
isValid={leftOptions.isValid}
handleChangeColor={leftOptions.handleChangeColor}
handleChangeCount={leftOptions.handleChangeCount}
/>
<Column
side="right"
color={rightOptions.color}
count={rightOptions.count}
isValid={rightOptions.isValid}
handleChangeColor={rightOptions.handleChangeColor}
handleChangeCount={rightOptions.handleChangeCount}
/>
</>
)
Not Destructuring with Spread
If we are careful with the naming of the properties in the object that our hook returns, we can use the spread syntax to dump props directly into our components.
The above component could be rewritten using the spread syntax like this:
const leftOptions = useItemOptions()
const rightOptions = useItemOptions()
return (
<>
<Column side="left" {...leftOptions} />
<Column side="right" {...rightOptions} />
</>
)
(Apparently, Dev.to syntax highlighting for the spread operator in JSX is not yet supported, but this works.)
Conclusion
We can return multiple values in several different ways that make sense at different times. Hopefully, this will give you some ideas about how to make your hooks more readable and easier to understand.
We have a bunch of options in our toolbelt here. There is overlap and there are trade-offs, so play around and figure out what makes sense for your application. And have fun!
Top comments (2)
Thanks for the very clear explanation of this - so helpful!
i've been looking all over the internet for this explanation. You made my day :D