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.

HomeTech
HomeTech
HomeTech
Unlock React 18 & 19: Core New Features and How to Use Them

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

useId

generates 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

useOptimistic

updates 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

useFormStatus

provides 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.

ReActhooksConcurrent ModeActionsServer ComponentsAuto Batching
HomeTech
Written by

HomeTech

HomeTech tech sharing

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.