Frontend Engineering

React Best Practices in 2026: What Changed Since React 18

Server Components, React 19 Actions, the compiler and data fetching: the React practices that changed since 2023 and what we use now.

React best practices have shifted from manually optimizing every component to choosing clear boundaries for server work, interactivity and data. React 19 Actions and the React Compiler change what you need to write yourself, but they do not remove the need to measure performance or design data flows carefully.

About the author: Jarosław Karpiński

What changed in React best practices since React 18?

The biggest change is that server rendering, form handling and performance optimization have more built-in support, so older rules need context rather than blind application. Server Components can keep some work off the browser, Actions help manage the progress and result of form submissions, and the React Compiler can reduce the need for manual memoization in supported setups.

That does not mean every application should adopt every feature. Your rendering setup, hosting environment, data sources and need for interactivity all affect which practices fit. Start by identifying the actual problem: slow initial pages, repeated data requests, awkward form states or code that is difficult to change. Then choose the smallest change that addresses it, rather than rebuilding the frontend around a new feature.

Should I use React Server Components in my application?

Use Server Components when your application benefits from preparing page content on the server, especially when that work involves reading data that should not be exposed to the browser. They can reduce the amount of browser-side code needed for content that does not require interaction, but they are not a universal performance switch.

A Server Component needs a server-capable setup; it is not a component you can simply add to any existing React page and expect to work. Components that need browser interactions, such as responding to a click or managing local input state, still belong on the client. Decide where that boundary should sit by tracing which parts of a page need interaction and which only display data. Moving too much across the boundary can make the application harder to reason about, not easier.

What are React 19 Actions, and should I use them for forms?

Actions are useful when a form or other user action needs a clear pending, success or error state. They let you connect an operation with its result in the interface, instead of piecing together separate state changes for every stage of a submission.

They are a good fit for common tasks such as saving a form or updating a record, provided your application’s server setup supports the behavior you want. They do not decide how your business operation should validate input, handle failures or protect sensitive data. Keep those responsibilities explicit, and make sure users can tell whether their action is still processing or needs attention. For a highly interactive workflow with complex intermediate steps, a custom state model may still be clearer.

Does the React Compiler mean I can stop using memoization?

Not entirely; it means you may not need to add manual memoization as a default response to every render. The compiler can optimize supported code automatically, but its benefits depend on your setup and on writing components in ways it can analyze.

First check whether users actually experience a performance problem. A component rendering again is not automatically a defect, and adding memoization everywhere can make code harder to maintain without making the page meaningfully faster. If an interaction feels slow, use a performance check to find the part of the page causing the delay before changing code. The Website Performance Scanner can help flag broader page performance issues, though it does not replace investigating a specific interaction in your application.

What is the right way to fetch data in React now?

Choose the fetching approach based on where the data is needed, how fresh it must be and what should happen when a request fails. When a server-capable framework is already part of your application, loading page data on the server can avoid making the browser fetch information it needs just to display the initial view.

For data that changes after a user interacts with the page, a client-side request may be appropriate. Be deliberate about loading and error states, duplicate requests, stale results and whether the displayed information needs refreshing. Do not assume that a particular request is cached or refreshed in a particular way without checking your framework’s behavior. In a product catalogue, for example, price and stock freshness may matter more than aggressive caching; the TanosMotorsport case study describes a storefront designed to refresh product prices and stock without a redeploy.

Are inline event handlers still a React performance problem?

Usually, no: writing an event handler inside a component is not, by itself, a reason to refactor it. The old blanket advice to avoid inline functions can lead to extra indirection without fixing anything users notice.

Pay attention when a measured issue points to repeated work, or when a new function reference prevents a memoized child from skipping an update. In that situation, check whether the child needs memoization at all, whether the component can be simpler, and whether the compiler handles the case in your setup. Keep handlers close to the behavior they describe unless you have a specific reason to move or stabilize them. That makes the code easier for the next person to follow.

Do I still need TypeScript for a React project?

TypeScript remains a practical choice when several people need to change the same application or when data crosses many screens and services. It can catch mismatches while you are working, but it cannot guarantee that information from an external service is valid at runtime.

Use it to make component inputs and important data shapes clear, rather than treating a type declaration as proof that incoming data is safe. For a small, short-lived interface with little changing data, adding TypeScript may not be the first improvement to prioritize. For a growing product, agree on how shared types are maintained and how external data is checked; otherwise, types can give a false sense of certainty while the underlying data changes.

When should I split code and lazy-load React components?

Split code when a part of the application is not needed for the first view and loading it later improves the experience without making the interface confusing. This often applies to large, secondary screens or features that users open only after choosing an action.

Avoid splitting every component just to make an initial download look smaller. Too many separate loads can delay the moment a user can complete a task, particularly when the page needs those components immediately. Check which screens matter at first load, how users move between them and whether a clear loading state is possible. If the initial page is already fast and the extra structure adds maintenance work, keep it simple.

Does React make my application GDPR-compliant?

No; choosing React does not make an application compliant with privacy requirements. Compliance depends on what personal data you collect, why you collect it, where it goes, how long you keep it and what choices users have.

Build privacy decisions into the product and its data flows rather than treating a consent banner as the whole solution. Check that analytics and other optional services behave according to the user’s choice, and avoid collecting information the feature does not need. The right implementation depends on the actual data and legal requirements, so involve the people responsible for privacy and compliance. Frontend code can support those decisions, but it cannot replace them.

How do you decide which React changes to make first?

Start with the user-visible problem, not the newest React feature. Check the slow or confusing journey, identify whether the cause is rendering, data loading, too much browser-side work or an unclear interaction, and then choose an approach that fits the application’s existing setup.

In practice, the right answer may be to add a server-rendered boundary, simplify a data request, defer a secondary feature or leave the code alone. For a product-led storefront, the TanosMotorsport case study shows one example of a decoupled frontend connected to a headless content system, with product information refreshed without redeploying. That is a project-specific design, not a rule that every React application needs the same architecture.

If you are weighing these changes for an existing product, talk through your React architecture with PixelHorizon.