How Hooks Are Built
When we build a custom hook with complex logic in React, we either return an array or an object that has state and logic. The following shows the process:
1. Returning an object
The first option is to return an object from the custom hook, like this:
const customHook = (configs) => {
const isLoading = true //logic
const reload = () => {/*logic*/}
return { isLoading, reload }
}
The usage would look like this:
const { isLoading, reload } = customHook(configs)
Where:
- It is developer-friendly, where you don’t need to remember the order of the props
- The IntelliSense will help you know the params
But when we use multiples of that hook, it doesn’t look nice. It will look like this:
const {
isLoading: isLoadingWidget1,
reload: reloadWidget1
} = customHook(widget1Config)
const {
isLoading: isLoadingWidget2,
reload: reloadWidget2
} = customHook(widget2Config)
const {
isLoading: isLoadingWidget3,
reload: reloadWidget3
} = customHook(widget3Config)
Which is not really nice. We have to rename each key to another one so they don’t clash.
2. Returning an array
The other option is to return an array from the custom hook, like the following:
const customHook = (configs) => {
const isLoading = true //logic
const reload = () => {/*logic*/}
return [isLoading, reload]
}
The usage would look like this:
const [isLoading, reload] = customHook(configs)
Where:
It solves the multiple usages problem. You don’t have to rename each key
But:
You have to maintain the order of props Doesn’t have the same IntelliSense as in Objects
Can We Combine the Options
Can we combine these patterns together? In a sense, if you want to use it as an array or as an object for the same hook.
Yes, that’s possible. Look at this implementation:
const customHook = () => {
const isLoading = true //logic
const reload = () => {/*logic*/}
const result = [isLoading, reload]
result.isLoading = isLoading
result.reload = reload
return result
}
result is an array, yet we add isLoading and reload keys to it.
That implementation will give us the ability to use the hook’s return value as:
- An object
const { isLoading, reload } = customHook(configs)
- An array
const [isLoading, reload] = customHook(configs)
Both of these options will work. But why…
Why Does That Work
Why is it possible to use both the Array and Object return types? Why is it possible to attach keys to an array?
“The Array object, as with arrays in other programming languages, enables storing a collection of multiple items under a single variable name, and has members for performing common array operations.” — MDN
As mentioned, “The Array object.” That reveals the fact that an array is actually just an object, with a special constructor, and a set of methods performing common array operations.
Proof that Array is actually an Object
Proof 1
typeof [] // 'object'
Yes, typeof will result in an 'object'
- Proof 2
const {0: first, 1: second} = [1, 2, 3, 4] // first: 1, second: 2
We can destruct the array object using the indices because the keys in any array are just the indices and values of the object, and they are what you pass between the brackets []. That’s why we’re able to destruct it and rename keys that way.
- Proof 3
const { length } = [1, 2, 3, 4]
An array is an object that also has length key in it.
- Proof 4
Object.keys([1, 2, 3, 4]) // ['0', '1', '2', '3']
Object.values([1, 2, 3, 4]) // [1, 2, 3, 4]
Object.keys and Object.values only work on Objects, and Array is an object (a special object).
Conclusion
We have just seen a pattern that allows us to make hooks’ return value to be destructed as an array or as an object. We’ve seen how that is helpful. And we’ve seen why that is possible because it’s all about the fact that Arrays are just Objects with a cap.
JavaScript concepts you need to know in order to get started with React