Unlock React 18 & 19: Core New Features and How to Use Them
This article explains React 18’s automatic batching, concurrent mode, new hooks, and root API changes, then dives into React 19’s server components, actions, optimistic updates, resource preloading, and native document metadata support, providing code examples for each feature.
React 18 Core New Features
React 18 introduces automatic batching, concurrent mode, new hooks such as useId and useDeferredValue, and an upgraded root API.
Automatic Batching
All state updates are now automatically batched across any context, reducing renders. The example below shows the difference between React 17 and React 18.
// React 17 (only batches inside event handlers)
const handleClick = () => {
setCount(c => c + 1); // triggers render
setFlag(f => !f); // triggers render
};
// React 18 (auto‑batch everywhere)
fetchData().then(() => {
setCount(c => c + 1);
setFlag(f => !f);
});When immediate rendering is required, flushSync can be used to force synchronous updates.
import { flushSync } from 'react-dom';
function handleClick() {
flushSync(() => setCounter(c => c + 1));
flushSync(() => setFlag(f => !f));
}Concurrent Mode
Concurrent Mode makes React interruptible, allowing high‑priority updates to pre‑empt low‑priority work. It powers features like Suspense, startTransition, and streaming SSR.
Example of startTransition:
import { useState, startTransition } from 'react';
function SearchBox() {
const [keywords, setKeywords] = useState('');
const [searchResults, setSearchResults] = useState([]);
const handleChange = e => {
setKeywords(e.target.value);
startTransition(() => {
performHeavySearch(e.target.value).then(results => {
setSearchResults(results);
});
});
};
return (
<>
<input value={keywords} onChange={handleChange} />
<SearchResults results={searchResults} />
</>
);
}New Hooks
useIdgenerates a stable unique ID across server and client. useDeferredValue delays non‑critical state updates, keeping the UI responsive.
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>Accept</label>
<input id={id} type="checkbox" />
</>
);
}React 19 Core New Features
React 19 adds Server Components, Actions for async data handling, optimistic updates, the new use hook, and native support for document metadata and resource preloading.
Server Components
Server Components render on the server, reducing client JavaScript, improving SEO and initial load time.
// Users.server.jsx
export default async function Users() {
const res = await fetch("https://api.example.com/users");
const users = await res.json();
return (
<div>
<h1>Users</h1>
{users.map(user => (
<div key={user.id}>
<h2>{user.name}</h2>
<p>{user.role}</p>
</div>
))}
</div>
);
}Actions
Actions let you write async functions that automatically manage pending state, optimistic updates, and error handling.
// React 19 – automatic state management
function Form() {
const [error, handleSubmit, isPending] = useActionState(async () => {
await fetch('/api');
});
return (
<form action={handleSubmit}>
<button disabled={isPending}>
{isPending ? 'Submitting...' : 'Submit'}
</button>
</form>
);
}Optimistic Updates
useOptimisticupdates the UI immediately before the server confirms success, rolling back on failure.
function ChangeName() {
const [name, setName] = useState("");
const [optimisticName, setOptimisticName] = useOptimistic(name);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
try {
await updateName(newName);
setName(newName);
} catch (e) {
console.error(e);
}
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<label>Change Name:
<input type="text" name="name" disabled={name !== optimisticName} />
</label>
</form>
);
}useFormStatus
useFormStatusprovides the nearest parent form’s state (pending, data, method, action).
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>;
}Ref as Prop (API Unification)
React 19 allows passing ref as a regular prop without forwardRef.
// React 19
export const Input = ({ ref }) => <input ref={ref} />;Preloading Resources
New APIs ( prefetchDNS, preconnect, preload, preinit) let you declare resource priorities for scripts, fonts, stylesheets, etc.
import { prefetchDNS, preconnect, preload, preinit } from "react-dom";
function MyComponent() {
preinit("https://.../script.js", { as: "script" });
preload("https://.../font.woff", { as: "font" });
preload("https://.../stylesheet.css", { as: "style" });
prefetchDNS("https://...");
preconnect("https://...");
}Document Metadata
React 19 natively renders , , and tags from any component, removing the need for third‑party libraries.
End of article.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
