Core Concepts

Next.js integration

Use rs-x inside Next.js client components with the same core rule as React: create the expression first, then pass that same expression instance to useRsxExpression.

What it means

In Next.js, useRsxExpression belongs in client components. Server components can fetch data or compose layout, but the actual RS-X hook subscription runs on the client.

The React part is the same as plain React: do not create a new bound expression during every render. Build the expression first, then pass that same expression instance to useRsxExpression.

The Next.js-specific difference is where that code can live. In plain React, the question is only how to create the expression. In Next.js, you also have to decide which part of the tree is a server component and which part is a client component.

Practical value

Next.js adds server and client boundaries, but the React hook behavior is still the same on the client side. If a client component creates a fresh RS-X expression during every render, the hook keeps seeing a new expression object instead of one long-lived expression to subscribe to.

When you create the expression at module scope or let useRsxExpression create it from a stable client-side model, the hook can stay connected to one expression instance and let RS-X drive the re-renders from normal model mutations.

Key points

Server Components vs Client Components

RS-X hook usage in Next.js starts with the normal React client component boundary. A server component cannot call useRsxExpression. Instead, put the hook inside a 'use client' component and let that client component own the RS-X model and expression, or import them from a shared client-side module.

This means the React guidance and the Next.js guidance are really the same guidance seen from two angles: Next.js determines where the hook is allowed to run, and React determines how the hook input should be created.

How Next.js Differs From React

If you already understand the React page, the hook behavior here is not new. The same rules about expression identity, disposal, and component-owned state still apply.

The extra decision in Next.js is architectural rather than hook-specific: decide which data preparation can stay on the server, then pass plain values into a client component that owns the RS-X model, expression, and user interaction.

Module-Scoped vs Component-Owned

Create the model and expression at module scope when you want the same model and expression to be reused by that file.

Use useMemo when the model should belong to a single mounted component instance. Memoize the model first, then let useRsxExpression create the bound expression from that model. That gives the component its own isolated RS-X state while still ensuring the hook keeps one long-lived expression instance.

What To Avoid

Avoid binding the expression inline during render. That pattern looks compact, but it creates a new expression every time the component renders. In React and Next.js client components, that can lead to confusing subscription churn and runtime issues because the hook is no longer attached to one consistent expression instance.

'use client';

import { rsx } from '@rs-x/expression-parser';
import { useRsxExpression } from '@rs-x/react';

export default function OrderPage() {
  const model = { price: 100, quantity: 3 };

  // Avoid this pattern in React / Next.js:
  // it creates a brand new expression during every render.
  const total = useRsxExpression(rsx<number>('price * quantity')(model));

  return <p>Total: {total}</p>;
}

useRsxExpression — pre-built IExpression example

Build the expression once at module scope and reuse it in a Next.js client component. The hook reads from that expression and updates when it changes, but it does not dispose the expression on unmount.

Preview

Edit the code and the preview recompiles from that updated source.

Live demo

Code

useRsxExpression — create with useMemo example

When the model belongs to the page or client component, memoize the model and let useRsxExpression create and dispose the bound expression for that component instance.

Preview

Edit the code and the preview recompiles from that updated source.

Live demo

Code

useRsxModel — full model binding example

Bind every scalar field in a model object. In a Next.js client component, the component can read those fields directly and the UI updates when the original model changes.

Preview

Edit the code and the preview recompiles from that updated source.

Live demo

Code

Expression change transactions example

Run the same two async updates with and without a transaction and compare the commit counter.

Preview

Edit the code and the preview recompiles from that updated source.

Live demo

Code

Installation example

Run rsx init in your Next.js project to install the right packages and apply the setup automatically. See the CLI docs.

rsx init