React Hooks, are super-powered functions that allow you to tap into React state and component lifecycle features from functional components. React Hooks are designed to only work in functional components and have backward compatibility. Before React Hooks developers used to work with class-based components to get access to features like component life cycle and the React State but with the Introduction and popularity of functional components Hooks were introduced to allow developers to get access to component life cycle, React State and other cool features from a functional component.
In today's post, we will talk about some of the most important React Hooks, that all React developers need to be familiar with, I suggest that you share with us some of your favorite React Hooks. We are going to be considering the following React Hooks in this post;
• useState
• useEffect
• useRef
• useContext
• useCallback
• useMemo
• Rules of React Hooks
useState
The useState hook allows you to track the state of your application, when we use the word state we mean a property or data that is bound to change and thus the UI needs to be updated according to the current value of the data. Let's say for instance you need to display how many times a button has been pressed by the user. The number of times the user has pressed the button is a state variable because it will change every single time the user presses the button and as such we need the UI to be updated each time to display the current value. Let's see a code example of what I mean.
const count = 0;
const App = () => (
<h3>You have pressed the button {count} times.</h3>
<button onClick={() => count++}>
update count
</button>
);
With the code we have above the count will be incremented each time the user presses the button but the UI will not update accordingly, now let's do the same with the useState hook.
import {useState} from 'react';
const App = () => {
const [count, updateCount] = useState(0)
return (
<h3>You have pressed the button {count} times.</h3>
<button onClick={() => updateCount(count++)}>
update count
</button>
);
}
First, we need to import the useState
hook from react. Next Inside the component at the top level before the return statement, we call the useState hook since it's just a function. Any value we pass to the useState
hook when we call it will be the initial value for the state. The function returns an array with two values which we destructure, the first Item in the array is the state we want to track while the second item is a function that updates the state thus triggering a UI rerender. Now anytime the user presses the button both the state and the UI will update accordingly.
useEffect
The useEffect hook is used to run a side effect in your components, The useEffect hook is fired on the initial UI render and every other time the UI renders. This hook is used to handle database subscriptions and some data mutations. Let's say you want to retrieve data from your API e.g. A user's profile, this is where the useEffect hook comes into play. Let's see an example of the useEffect hook in action.
import {useState, useEffect} from 'react';
const App = ({ userId }) => {
const [user, updateUser] = useState({});
useEffect(() => {
const getUser = async (id) => {
const currentUser = await getUserSomehow(id);
updateUser(currentUser);
}
getUser(userId)
}, [userId]);
return (
<h1>Hello, {user.name}</h1>
)
}
First, we need to import the useEffect hook from react
then we call it at the top level of the function component before the return statement. This hook accepts two arguments, The first is a callback function that will be fired each time the UI renders while the second is an optional array of values that will determine if the side effect should be triggered each time any of the values changes. In the example above, since we have included the userId
in the dependency array to the useEffect hook, each time the userId
changes the component will run the useEffect callback.
The callback function we pass to the useEffect hook cannot be a promise, instead, we can create an async function inside the callback function to run the subscription and call it still inside the callback function just as we did above. I have also included another useState
hook just to demonstrate how they work together.
useRef
The useRef
Hook creates a mutable ref object that can be used to access a DOM element or other value. Since we are using react you are not expected to use the document.querySelector
API, thus to grab an element out of the DOM you can use the useRef
hook. The hook can also be used to preserve values between component rerender. Let's see an example of how to grab an element with the useRef
hook.
import {useRef} from 'react';
const App = () => {
const para = useRef()
const copy = () => {
navigator
.clipboard
.writeText(para.current.innerText)
alert('copied');
}
return (
<div>
<p ref={para}>0XCEDD234SDCS.....</p>
<button onClick={copy}>Copy</button>
</div>
);
}
First, we import the useRef hook from the react. Then we create a mutable ref object which we will assign to the paragraph element. Next, we define a copy function which is used to copy the text of the paragraph to the clipboard. Then, the function uses the navigator.clipboard.writeText()
method to write the text in the paragraph using the innerText property to the clipboard. The UI returns a div element that contains a paragraph and a button. The paragraph has the text that the user wants to copy. The button has an onClick event handler that calls the copy function. We use the ref prop to bind the para ref object to the paragraph element. This allows the copy function to access the paragraph element.
useContext
The useContext
hook is used to manage the global state. What do we mean by a global
state? There are some values that you want to access inside all your components no matter how deeply nested that component is in the component hierarchy so instead of passing props from component to component, what you can do is use the useContext
hook to create a global state that can be accessed from any component no matter how deeply nested it is. To use this hook first we need to create a context inside the root component. Then you need to wrap that root component with a context provider. Inside the child component or any other component we intend to access the value stored in the global state, we can use the useContext hook.
import {createContext} from 'react';
import App from './app';
export const ThemeContext = createContext();
const Root = () => {
const theme = { color: '#000', bg: 'red' };
return (
<ThemeContext.Provider value={theme}>
<App />
</ThemeContext>
);
}
As discussed we have imported the createContext
function from react then we use it to create a ThemeContext
. We have also created a theme object. Next, We wrap the root component with the ThemeContext.Provider
which accepts a value prop, here we just pass the theme object as the value to the context provider. Now let's see how we can use this inside a deeply nested component.
import {useContext} from 'react'
import {ThemeContext} from './root';
const Component = () => {
const theme = useContext(ThemeContext)
return (
<h1 style={{ color: theme.color }}>Theme</h1>
);
}
useCallback
The useContext hook is used to create a memoized callback function.
A memoized callback is a function that is stored in memory and only re-created if its dependencies change. This improves performance by preventing unnecessary re-rendering of components.
In React, callbacks are often used as event handlers. When a callback is used as an event handler, it is called whenever the event occurs. If the callback is not memoized, it will be re-created every time the event occurs, even if the callback function itself does not change. This can lead to unnecessary re-rendering of the component. Let's see an example of the useCallback
hook in action.
import {useCallback} from 'react';
import {useRouter} from 'next/router'
const App = () => {
const router = useRouter();
const goBack = useCallback(() => {
router.back()
}, [router]);
return (
<div>
<button onClick={goBack}>Increment</button>
<p>current page</p>
</div>
);
};
useMemo
The useMemo
hook is very much similar to the useCallback
hook however the useMemo
hook will return a memoized value instead of a function that only changes if one of its dependencies has changed. The useMemo
hook returns a memoized version of the value returned by the function. The memoized version of the value is created when the component first renders, and it is updated only if one of the dependencies changes. Let's see an example of it;
const App = () => {
const [number, setNumber] = useState(0);
const factorial = useMemo(() => {
return Math.factorial(number);
}, [number]);
return (
<div>
<input type="number" value={number} onChange={(e) => setNumber(e.target.value)} />
<p>The factorial of {number} is: {factorial}</p>
</div>
);
};
In the example we have above, the factorial function calculates the factorial of the number passed to it. The useMemo hook is used to memoize the factorial function so that it is only re-created if the number state changes.
Rules of React hooks
Now we've discussed some of the most basic react hooks you should know that there are rules to using react hooks so let's go over them;
- Hooks must be called within a functional component. Hooks cannot be used in class components.
- Hooks cannot be nested. You cannot call one hook from within another hook.
- Hooks can only be used at the top level of your component. This means that you cannot use hooks in functions.
That's it for this piece on react hooks, I hope you found this useful Please leave your thoughts about react hooks and definitely share your favorite react hooks for us. If there are some hooks that I left out and you feel it should have made the list, do well to discuss them in the comment section below and I will see you in the next post.
Top comments (2)
Very nice and concise explanation of hooks. Gave me a good refresher on a couple I don't use too often. Good stuff!
Thanks Joe, I'm glad you found this piece useful