In this article we will see about react hooks and their usage. Before starting I assume you have decent knowledge of react and this post will help you to polish your information about react hooks so let’s begin.
Introduction.
In React.js v-0.14 the functional component was introduced. Before this only class components were in used and functional component was stateless. Later in React v-16.8 they introduced hooks for functional component for managing state. Initially hooks like useState and useEffect was in use but letter they introduced lots of useful hooks for simplifying UI development.
What are hooks in react.js?
In class component we were using setState to mange the state. Similarly in functional component we use hooks to for managing the state with many other advantages. It allows functional component to have access to the state and other react features. Due to this rich features of functional component the class components are no longer needed.
Creating custom hook is also possible. Hook is just JavaScript function which takes inputs and gives output accordingly. For ex. We have built-in hooks like useState and useEffect similar we can create another custom hooks like useWindowSize, useFetch, useDebounce, useLocalStorage etc.
useState and useEffect are mostly used hooks and I think you already have enough ideas about its usage. Let’s see the other types of React hooks that you can use in your project effectively.
1. useMemo
React hook useMemo memoizes or cache the result of calculation between re-renders. So it will only rerun if there is change in give dependency.
Usage -
1. Prevent unnecessary re-renders
2. Caches the result and skips expensive recalculation
const memoizedSum = useMemo(() => {
return sum(a, b);
}, [a, b]);
Here in this example , The function will calculate the sum only if there is change in a or b otherwise it will directly execute the same result of sum.
FYI - In React component when you set any state or there is change happening in values then re-renders will happen for another functions also(in same component. While child component will not be affected until its props changed ). Resulting unnecessary things will also run and will cause performance issue. So useMemo will help you to stop unnecessary re-renders and improve the performance of your site .
function MyComponent() {
const [count, setCount] = useState(0);
function sayHello() {
console.log('hello');
}
console.log('Component rendered');
return (
<div>
<button onClick={sayHello}>Say Hello</button>
…
</div>
);
}
Here when state change all function inside it will re-render which is unnecessary and cause performance issue.
function MyComponent() {
const [count, setCount] = useState(0);
const [other, setOther] = useState(0);
const sumValues = useMemo(() => {
console.log('Calculating...');
let total = 0;
for (let i = 0; i < 100000000; i++) {
total += count;
}
return total;
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increase Count</button>
<button onClick={() => setOther(other + 1)}>Change Other</button>
<p>Expensive: {expensiveValue}</p>
</div>
);
}
Here all the function will re execute but because of memo sumValues will only recalculate if count changes.
2. useCallback.
useCallback hook lets you memoize the function definition so that it will render the function only if the dependency changes. Simply it cached the function.
Benefits:
1. Avoid unnecessary re-render especially when function passes to the child component.
2. You can update state from memoized callback
3. React will not call function itself. You will decide when and whether to call the function by considering its dependencies.
const handleSubmit = useCallback( (orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
},
[productId, referrer]
);
In this code :
useCallback memoizes the handleSubmit
It only changes if productId or referrer changes.
Avoids recreating handleSubmit on every render
3. useRef
useRef is one of the important hook in React UI development. It has following features
1. It create mutable reference that persist the value across the render
2. It is also use to access all the properties of DOM element.
3. Does not trigger re-render when its value changes.
Main purpose - It does not cause DOM re-render or refresh. It’s just change .current value quietly. Perfect for keeping data without triggering UI updates.
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus(); // focuses the input on mount
}, []);
return <input ref={inputRef} />;
}
useRef returns only one item. And .”current” is its property to access values of DOM element in form of object.
const myRef = useRef();
{ current: ... }
Note: Do not use ref.current during rendering except initializing. It will cause unpredictable behavior of component.
4. useImperativeHandle
useImperativeHandle is a very useful React hook when you want to run a function defined in a child component from the parent. In simple terms, it allows you to expose specific functions or properties from the child to the parent via a ref.
It works together with forwardRef to give parent controlled access to the child methods.
-> Child component
const childFun = forwardRef(_, ref=>{
useImperativeHandle(ref, () => ({
getData: () => updateNewData(),
}));
const updateNewData=()=>{
…
}
})
export default childFun;
-> Parent Component
Import ChildFun form “./child”
const parentFun = ()=>{
const childRef = useRef()
const click = ()=>{
childRef?.current?.getDate();
}
return(
<Child ref={childRef}/>
<button onclick={click}></button>
)
}
In this way you can pass refs or even run functions of child component from parent with the help of forwarRef and this hook called as useImperativeHandle.
#Use Case
You’ll often encounter situations where there are multiple groups with multiple subgroups within a single group. This hook can help you streamline access, data collection, and nested operations, making your work more efficient.
5. useContext
If you want to use the same props in many components then useContext is hooks that provide where you can manage state globally.
This react feature is useful when you have many child components and require same props values throughout all the children.
You will need to create context provider inside which all the children will be exist. And that all children will have access of that same value.
Steps to implementation
1. Create context
2. Provide context value in provider
3. Access that context value in the all children
Creating context (separately)
#AgeContext
import { createContext } from 'react';
export const AgeContext = createContext();
import { AgeContext } from ‘./contexts/AgeContext';
function App() {
return (
<AgeContext.Provider value="16">
... <Childs />
</AgeContext.Provider>
);
}
#child
import { useContext } from 'react';
import { AgeContext } from './ThemeContext';
function Page() {
const category = useContext(AgeContext);
return (
<div>
You are viewing list of ${category} Age old people.
</div>;
)
}
#Use Case
Wrapping up all the child components inside parent will have access of provided values. no matter how nested structure it is.
useContext hook is part of Context api in React.js. This is built in feature in React to provide global values deeply inside the parent.
#Caveats.
This hook is works like Redux/Recoil (useContext is suitable for parent component and its children to use same value, It is not suitable for global use like Redux) but if overused it can create unnecessary re-renders. For complex logic it is not suitable choice.