New Hooks in React 18
React’s state, representing dynamic component data, is integral for effective component management. Initially confined to class components and managed using this.setState
, the introduction of React Hooks in version 16.8 extended state usage to functional components. Hooks, functions enabling state and lifecycle management in functional components, provide a more versatile approach to React development.
There are several built-in hooks in React, today we are going to see new React hooks that are introduced in React 18.
Table of Content
- useId
- useDeferredValue
- useTransition
- useSyncExternalStore
- useInsertionEffect
useId:
useId hook is one of the simplest hooks in react js and it is used to generate unique id’s for related elements on both client-side and server-side. The useOpaqueIdentifierhook was used before useId but it did contain some bugs and had its limitations with react 18 update react introduced useId with bug fixes.
Importing useId hook:
import { useId } from "react"
Syntax:
const id = useId()
useId does not take any parameters.
Example: below is the practical example of useId hook
Javascript
import Component from "./Component" ; function App() { return ( <div className= "App" > <Component /> <p> This is Paragraph </p> <Component /> </div> ); } export default App; |
Javascript
import React, { useId } from 'react' function Component() { const id = useId() return ( <div> <label htmlFor={id}>Field 1:</label> <input type= "text" id={id} /> </div> ) } export default Component |
Output:
useDeferredValue:
- In React 18, addressing sluggish rendering is a key goal, and
useDeferredValue
anduseTransition
hooks are introduced for this purpose. - When rendering a component multiple times for a large number of inputs, React’s efficiency can be compromised, leading to delays and slower render times.
useDeferredValue
is a React Hook that postpones updating a portion of the UI. It introduces a delay in updating the hook value, enhancing user experience by preventing immediate rendering and allowing a smoother display of characters as the user types.
Importing:
import { useDeferredValue } from 'react'
Syntax:
const deferredValue = useDeferredValue(value);
Example: below is the practical example of useDeferredValue hook
Javascript
import React, { useState } from 'react' ; import DisplayInput from './DisplayInput' ; function App() { const [userInput, setUserInput] = useState( '' ); const handleInputChange = (e) => { setUserInput(e.target.value); }; return ( <div> <label htmlFor= "userInput" > Enter Text: </label> <input type= "text" id= "userInput" value={userInput} onChange={handleInputChange} /> <DisplayInput input={userInput} /> </div> ); } export default App; |
Javascript
import React, { useDeferredValue } from 'react' ; function DisplayInput({ input }) { const deferredValue = useDeferredValue(input); const renderInputs = () => { const inputs = []; for (let i = 0; i < 20000; i++) { inputs.push( <div key={i}> {deferredValue} </div> ); } return inputs; }; return ( <div> <h2> Displaying {deferredValue} </h2> {renderInputs()} </div> ); } export default DisplayInput; |
Output: There is no delay in updation of input in input box.
useTransition:
useTransition
addresses performance concerns in React applications by enhancing UI responsiveness, ensuring a smoother user experience even during background processing.- In scenarios like a search component with dynamic filtering, where multiple states are updated simultaneously (e.g., search input and filtered results), React’s default high-priority updates can lead to potential slowdowns.
- The issue arises when managing numerous user inputs, causing delays in updating states and impacting user interaction.
useTransition
resolves this by allowing low-priority state updates through the startTransition function, preventing UI blocking and optimizing overall performance.
Import:
import { useTransition } from 'react'
Syntax:
const [isPending, startTransition] = useTransition()
Example: below is the practical example of useTransition hook
Javascript
import React from 'react' ; import SearchList from './SearchList' ; function App() { return ( <div> <SearchList /> </div> ); } export default App; |
Javascript
import React, { useState, useTransition } from 'react' ; const namesList = [ 'Alice' , 'Bob' , 'Charlie' , 'David' , 'Eva' , 'Frank' // ... Add more names as needed ]; function SearchList() { const [searchTerm, setSearchTerm] = useState( '' ); const [filteredNames, setFilteredNames] = useState(namesList); const [isPending, setTransition] = useState(); const handleSearch = (e) => { const term = e.target.value.toLowerCase(); setSearchTerm(term); setTransition(() => { const filtered = namesList.filter( name => name.toLowerCase() .includes(term) ); setFilteredNames(filtered); }) }; return ( <div> <label htmlFor= "search" > Search: </label> <input type= "text" id= "search" value={searchTerm} onChange={handleSearch} placeholder= "Type to search names" /> <ul> { filteredNames.map((name, index) => ( <li key={index}> {name} </li> )) } </ul> </div> ); } export default SearchList; |
Output:
useSyncExternalStore:
- React commonly uses internal states, but
useSyncExternalStore
comes into play when states are managed by third-party libraries or browser APIs outside React. - This hook allows subscription to external stores, like global state in Redux or data in browser APIs (e.g., localStorage), ensuring components re-render upon changes in the external store.
Import:
import { useSyncExternalStore } from 'react'
Syntax:
const variable_name = useSyncExternalStore(subscribe, getSnapshot, [getServerSnapshot]?)
Example: below is the practical example of useSyncExternalStore hook
Javascript
import React from 'react' ; import ResizableElement from './BatteryStatusIndicator' ; function App() { return ( <div> <ResizableElement /> </div> ); } export default App; |
Javascript
import { useSyncExternalStore } from 'react' export default function ResizableElement() { const subscribe = (listener) => { window.addEventListener( 'resize' , listener) return () => { window.removeEventListener( 'resize' , listener) } } const width = useSyncExternalStore(subscribe, () => window.innerWidth); return ( <div> <p>Size: {width}</p> </div> ) } |
Output:
useInsertionEffect:
useEffect
executes a function after component rendering, whileuseInsertionEffect
is designed for inserting elements into the DOM before layout effects, like dynamic styles, without server rendering.useInsertionEffect
is specialized for pre-layout element insertion, running only on the client side and not during server rendering.
Import:
import { useInsertionEffect } from 'react';
Syntax:
useInsertionEffect(()=>{
// Insert dynamic styles before layout effects fire
return()=>{
//cleanup function
}
}, [])
Example: This exampe implements UseInsertionEffectHook in React
Javascript
import React from 'react' ; import UseInsertionEffectHook from './BatteryStatusIndicator' ; function App() { return ( <div> <UseInsertionEffectHook/> <br/> <br/> <button>First</button> <button>Second</button> </div> ); } export default App; |
Javascript
import { useInsertionEffect, useState } from "react" ; export default function UseInsertionEffectHook() { const [theme, setTheme] = useState( 'dark' ) useInsertionEffect(() => { const styleRule = getStyleRule(theme); document.head.appendChild(styleRule); return () => document.head.removeChild(styleRule) }, [theme]) return <button onClick={ () => setTheme(theme === 'dark' ? 'white' : 'dark' )}> Change theme </button> } const getStyleRule = (theme) => { const tag = document.createElement( 'style' ) tag.innerHTML = ` button { color: ${theme === 'dark' ? 'white' : 'black' }; background-color : ${theme === 'dark' ? 'black' : 'white' }; } ` return tag } |
Output: