React Hooks are a very powerful feature of React which allows us to use state and other React features without writing a class.
In this article, we will discuss some of the uncommon React Hooks and their use cases.
useLayoutEffect
The useLayoutEffect hook is similar to useEffect but it fires synchronously after React has calculated the dimensions for all the DOM nodes browser needs to paint, and before browser paints the screen.
It is useful for performing DOM mutations or measuring the layout of the DOM elements, before the browser paints the screen, so that the user doesn’t see any flickering or layout shifts.
Simple as that, if you want to perform some side effects that need to happen before the browser paints the screen, you can use useLayoutEffect instead of useEffect.
useDeferredValue
The useDeferredValue hook is used to defer the value of a state until the browser is idle.
It is useful for improving the performance of a component by deferring the rendering of a component until the browser is idle.
It is just like debouncing a value, but it is more efficient than debouncing because it doesn’t require a timer.
Let me give you an example -
import { useDeferredValue } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const deferredSearchTerm = useDeferredValue(searchTerm);
return (
<div>
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<SearchResults query={deferredSearchTerm} />
</div>
);
}
Here, SearchResults component will only re-render when the browser is idle, which can improve the performance of the component if the search results are expensive to render.
useTransition
The useTransition hook is used to mark a state update as a transition.
It can mark low-priority updates as transitions, which allows React to interrupt the rendering of a component if a higher-priority update comes in.
It gives an array of two values -
- A boolean value that indicates whether the transition is pending or not.
- A function that can be used to start a transition.
Here is an example of how to use useTransition -
import { useTransition } from 'react';
function MyComponent() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
const handleClick = () => {
startTransition(() => {
setCount((c) => c + 1);
});
};
return (
<div>
<button onClick={handleClick}>Increment</button>
{isPending ? 'Loading...' : count}
</div>
);
}
Here, setting the count state is marked as a transition, which means that if there is any higher-priority update (like a user interaction), React can interrupt the rendering of the component and show the loading state instead.
useDebugValue
The useDebugValue hook is used to display a label for custom hooks in React DevTools.
It won’t work when used in a regular component, it is only meant to be used in custom hooks.
Here is an example of how to use useDebugValue -
import { useDebugValue } from 'react';
function useMyCustomHook() {
const [value, setValue] = useState(0);
useDebugValue(value > 5 ? 'High' : 'Low');
return [value, setValue];
}
It can be used to debug custom hooks by providing a label that can be displayed in React DevTools, which can help us understand the state of the custom hook at a glance.
It also takes a second argument which is a function that can be used to format the value before displaying it in React DevTools.
import { useDebugValue } from 'react';
function useMyCustomHook() {
const [value, setValue] = useState(0);
useDebugValue(value, (val) => `Value is ${val}`);
return [value, setValue];
}
This function will execute only when the component is being inspected in React DevTools, so it won’t have any performance impact on the application.
It also won’t run in production mode, so it is safe to use without worrying about performance issues.
useImperativeHandle
The useImperativeHandle hook is used to customize the instance value that is exposed to parent components when using ref.
Its better to understand this with an example -
import { useImperativeHandle, forwardRef } from 'react';
const MyComponent = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
return <input ref={inputRef} />;
});
Now, if a ref is passed to MyComponent, it will have a focus method that can be called to focus the input element inside MyComponent.
It is useful is operations need to be performed on multiple child elements, and we want to expose a single method to the parent component to perform those operations.
useId
The useId hook is used to generate a unique ID that can be used for accessibility purposes.
It is useful for generating unique IDs for elements that need to be associated with a label, such as form inputs and their corresponding labels.
Here is an example of how to use useId -
import { useId } from 'react';
function MyComponent() {
const id = useId();
return (
<div>
<label htmlFor={id}>Name:</label>
<input id={id} />
</div>
);
}
React takes care of generating a unique ID for each instance of MyComponent, which ensures that the label is correctly associated with the input element, even if there are multiple instances of MyComponent in the application.
useEffectEvent
The useEffectEvent hook is used to create an event handler that can access the latest state and props.
It is useful for creating event handlers that need to access the latest state and props without having to worry about stale closures.
It is also useful when you don’t want to re run the effect every time the state or props change, but you still want to have access to the latest state and props in the event handler.
Here is an example of how to use useEffectEvent -
import { useEffectEvent } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const handleClick = useEffectEvent(() => {
console.log('Count is:', count);
});
return (
<div>
<button onClick={handleClick}>Log Count</button>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
</div>
);
In this example, the handleClick event handler will always log the latest value of count, even if it is called after the state has changed, without having to worry about stale closures or re-running the effect every time the state changes.