Custom Hooks should be used when you notice yourself doing the same thing over and over again
🔂 in different components.
From version 16.8, React Hooks are officially added to React.js. Besides built-in Hooks such as: useState
, useEffect
, useContext
,useCallback
…,
we can define our own hooks to use
state
andother React features
without writing a class😲.
In addition to the familiar Hooks like useState
, useEffect
, useRef
…, React also allows us to create custom Hooks with unique features that extract component logic into reusable functions.
Let’s take a look at the “what,” “how,” and “why” of writing our own Hooks😄.
What is a “Custom Hook?”🤔
"Building your own Hooks lets you extract component logic into reusable functions." -React Documentation
A custom Hook is really just a reusable function that follows the rules of Hooks:
- Starts with “use”, i.e.
useLocalStorage
oruseEventListener
- Only calls other Hooks at the
top level.
- The Hook function is just like a normal function except it does not return any HTML, but instead, returns state functions and attributes.
- To use the hook import it and use it within any other functional component.
Example
The functionfunction MyProfile(){ const auth = useAuth() }
useAuth()
is a hook.
It’s important that custom Hooks follow the useHook
naming convention because it allows React tooling to ensure you’re following all the rules of Hooks and tells other developers what they’re dealing with.
Calling Hooks at the “top level”
just means that we’re not doing it inside of loops, conditions, or nested functions. Hooks need to be called in the same order each time a component renders, so our calls have to stay outside of any program flow controls,
like if statements.
when to use React custom hook?😶
– When a piece of code (logic) is reused in many places
(it’s easy to see when you copy a whole piece of code without editing anything, except for the parameter passed. Split like how you separate a function).
– When the logic is too long and complicated
, you want to write it in another file, so that your component is shorter and easier😉 to read because you don’t need to care about the logic of that hook anymore.
Detailed Explanation using example😃
Let’s take a look at an example.
- we are going to be creating a new custom hook called
useCounter
. This hook will make it possible to reuse logic for a simple counter.
We are going to tackle this in two parts🤫
- First half we are going to implement a counter.
- In the second half we are going to extract the reusable logic into a
custom hook.
So let's begin.😉
I am going to create a new file called counterOne.js
. For the counter we need 3 basic scenarios.
- increment the counter
- decrement the counter
- reset the counter value
//1. first import useState from react
import React, { useState } from 'react'
function CounterOne() {
const [count, setCount] = useState(0);
//we define three methods increase,decrease and reset
const increment = () => {
setCount(prevCount => prevCount + 1)
}
const decrement = () => {
setCount(prevCount => prevCount - 1)
}
const reset = () => {
setCount(0)
}
return (
<div>
<h2>Count = {count}</h2>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
)
}
export default CounterOne
Now let's say we need the exact same counter functionality in a different component🤔
- let's create a new file called
CounterTwo.js
And copy the same code fromCounterOne
and change its nameCounterTwo
. - finally include component in
App.js
//This is CounterTwo component
import React, { useState } from 'react'
function CounterTwo() {
const [count, setCount] = useState(0);
//we define three methods increase,decrease and reset
const increment = () => {
setCount(prevCount => prevCount + 1)
}
const decrement = () => {
setCount(prevCount => prevCount - 1)
}
const reset = () => {
setCount(0)
}
return (
<div>
<h2>Count = {count}</h2>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
)
}
export default CounterTwo
If you now take a look at the browser🧐 our second counter should also work as expected.
But we do have one problem🤯
we are duplicating the code and how do we improve this?😟
the answer is creating a
custom hook
🤠
- Create a new file
useCounter.js
this will be ourcustom hook
for reusing counter functionality. - Next, we are going to
extract the reusable logic from the component
and added it to thecustom hook.
So remove the state variable along with the methods from components and paste it in
useCounter.js
So now our custom hook has reusable logic but we need a way to access the
count value and these methods
from our component.So instead of returning any
jsx
our custom hook is going to return anarray of values.
//This is our useCounter hook
import { useState } from 'react'
function useCounter() {
//we have extracted this from our component which were using same logic
const [count, setCount] = useState(0);
const increment = () => {
setCount(prevCount => prevCount + 1)
}
const decrement = () => {
setCount(prevCount => prevCount - 1)
}
const reset = () => {
setCount(0)
}
// our custom hook is going to return an `array of values.`
return [count, increment, decrement, reset]
}
export default useCounter
- By doing this now we can access the value and the methods using
array destructuring
in the component.
import React from 'react'
import useCounter from './useCounter'
function CounterOne() {
//This is where we are using our hook in component instated of same code
const [count, increment, decrement, reset] = useCounter()
return (
<div>
<h2>Count = {count}</h2>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
)
}
export default CounterOne
//same array destructuring in CounterTwo Component
const [count, increment, decrement, reset] = useCounter()
Our Component still works as expected😯 but this time we have written better code using our custom hook useCounter
😮💨
Custom hooks benefits🤠
- Completely separate logic from the
user interface
. - Reusable in many different components with the same processing logic. Therefore, the logic only needs to be fixed in one place if it changes.🤓
- Share logic between components.
- Hide code with complex logic in a component, make the component easier to read.
Conclusion🙆♀️
Custom Hooks enable exceptional flexibility
in sharing logic previously unavailable in React components.
I hope this guide has given you a better understanding of creating your own React Hooks.
Thank you for reading.🥰