Table of contents
React 18 has introduced 5 new hooks :
React 18 New Hooks
useId
useTransition
useSyncExternalStore
UseDeferredValue
useInsertionEffect
In this blog we will be covering 3 new hooks:
useId
useTransition
useSyncExternalStore
1. useId
- UseId is a hook that is used to generate unique Ids.
- UseId is evolved from
useOpaqueIdentifie
, which generates an opaque id that cannot be operated upon. - We can also add prefix/suffix to the Id.
In any web application, there are many cases where we need unique Ids
for example:
<label for="ID">
, where thefor
attribute must be equal to theid
attribute of the related element to bind them together.
function NameFields() {
const id = useId();
return (
<div>
<label htmlFor={id + '-firstName'}>First Name</label>
<div>
<input id={id + '-firstName'} type="text" />
</div>
<label htmlFor={id + '-lastName'}>Last Name</label>
<div>
<input id={id + '-lastName'} type="text" />
</div>
</div>
);
}
This code generated unique Ids for everyElement
As the Ids generated by useIds are globally unique and the suffix/preffix we add will be locally unique which will make the ids globally unique so it will not cause any hydration mismatch during server-side rendering
2. useTransition
- This hook is used for transition. It returns the transition state and function to start the transition.
By default, all updates in React are considered urgent. That could create a problem when quick updates are slowed down by heavy updates. But in React 18 and the new concurrency features, we can mark some updates as interruptible and non-urgent — so-called transitions. That's especially useful with heavy UI updates, like filtering a big list.
With the use of useTransition() hook we can access concurrent mode features inside of the React component.
const [isPending, startTransition] = useTransition();
- isPending: indicates that the transition is pending
- startTransition(callback): this allows us to mark any UI updates inside the callback as transitions.
import { useTransition } from 'react';
function MyComponent() {
const [isPending, startTransition] = useTransition();
// ...
const someEventHandler = (event) => {
startTransition(() => {
// Mark updates as transitions
setValue(event.target.value);
});
}
return <HeavyComponent value={value} />;
}
As already mentioned, we can use useTransition() hook to let know React which UI updates are urgent (like updating the input field value), and which are non-urgent transitions (like updating the names list to highlight the query).
Let's see the example below:
First, let's invoke the [isPending, startTransition] = useTransition() hook to get access to startTransition() function. Secondly, let's create a state variable to hold the query state value specifically for the transition.
export function FilterList({ names }) {
const [query, setQuery] = useState('');
const [highlight, setHighlight] = useState('');
const [isPending, startTransition] = useTransition();
const changeHandler = ({ target: { value } }) => {
setQuery(value);
startTransition(() => setHighlight(value));
};
return (
<div>
<input onChange={changeHandler} value={query} type="text" />
{names.map((name, i) => (
<ListItem key={i} name={name} highlight={highlight} />
))}
</div>
);
}
3.useSyncExternalStore
useSyncExternalStore is a hook recommended for reading and subscribing from external data sources (stores).
Here is the signature of the hook:
const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
This method accepts three arguments:
subscribe
: It is a function to register a callback that is called whenever the store changes.getSnapshot
: It is function that returns the current value of the store.getServerSnapshot
: It is function that returns the snapshot used during server rendering. This is an optional parameter. This method returns the value of the store, state.
We create an example of useSyncExternalStore, which reads the current browser window width and displays it on the screen.
import { useSyncExternalStore } from 'react';
function App() {
const width = useSyncExternalStore(
(listener) => {
window.addEventListener('resize', listener);
return () => {
window.removeEventListener('resize', listener);
};
},
() => window.innerWidth
// () => -1,
);
return <p>Size: {width}</p>;
}
export default App;
The above application calls useSyncExternalStore:
- subscribe (lines 5–10): It registers a callback for the window resize event listener.
- getSnapshot (line 11): It returns the current browser window width.
- getServerSnapshot (line 12): It is for server rendering, which is not needed here, or simply returns -1. Execute the code by npm start. The following video shows that the UI displays the browser window width while resizing.