Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 78 additions & 35 deletions src/content/reference/rsc/server-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ Server Functions can be created in Server Components and passed as props to Clie

## Usage {/*usage*/}

### Creating a Server Function from a Server Component {/*creating-a-server-function-from-a-server-component*/}
### Creating a Server Function in a Server Component {/*creating-a-server-function-from-a-server-component*/}

Server Components can define Server Functions with the `"use server"` directive:

```js [[2, 7, "'use server'"], [1, 5, "createNoteAction"], [1, 12, "createNoteAction"]]
// Server Component
import Button from './Button';

function EmptyNote () {
function EmptyNote() {
async function createNoteAction() {
// Server Function
'use server';

await db.notes.create();
}

return <Button onClick={createNoteAction}/>;
return <Button onClick={createNoteAction} />;
}
```

Expand All @@ -62,59 +62,64 @@ When React renders the `EmptyNote` Server Component, it will create a reference
export default function Button({onClick}) {
console.log(onClick);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
return <button onClick={() => onClick()}>Create Empty Note</button>
return <button onClick={() => onClick()}>Create Empty Note</button>;
}
```

For more, see the docs for [`"use server"`](/reference/rsc/use-server).


### Importing Server Functions from Client Components {/*importing-server-functions-from-client-components*/}
### Importing a Server Function into a Client Component {/*importing-server-functions-from-client-components*/}

Client Components can import Server Functions from files that use the `"use server"` directive:

```js [[1, 3, "createNote"]]
```js [[1, 4, "createNote"]]
// actions.js
"use server";

export async function createNote() {
await db.notes.create();
}

```

When the bundler builds the `EmptyNote` Client Component, it will create a reference to the `createNote` function in the bundle. When the `button` is clicked, React will send a request to the server to execute the `createNote` function using the reference provided:

```js [[1, 2, "createNote"], [1, 5, "createNote"], [1, 7, "createNote"]]
```js [[1, 4, "createNote"], [1, 7, "createNote"], [1, 9, "createNote"]]
// EmptyNote.js
"use client";

import {createNote} from './actions';

function EmptyNote() {
console.log(createNote);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNote'}
<button onClick={() => createNote()} />
return <button onClick={() => createNote()}>Create Empty Note</button>;
}
```

For more, see the docs for [`"use server"`](/reference/rsc/use-server).

### Server Functions with Actions {/*server-functions-with-actions*/}
### Calling a Server Function from an Action {/*server-functions-with-actions*/}

Server Functions can be called from Actions on the client:

```js [[1, 3, "updateName"]]
```js [[1, 4, "updateName"]]
// actions.js
"use server";

export async function updateName(name) {
if (!name) {
return {error: 'Name is required'};
}
await db.users.updateName(name);
return {error: null};
}
```

```js [[1, 3, "updateName"], [1, 13, "updateName"], [2, 11, "submitAction"], [2, 25, "submitAction"]]
```js [[1, 5, "updateName"], [1, 15, "updateName"], [2, 13, "submitAction"], [2, 28, "submitAction"]]
// UpdateName.js
"use client";

import {useState, useTransition} from 'react';
import {updateName} from './actions';

function UpdateName() {
Expand All @@ -123,40 +128,60 @@ function UpdateName() {

const [isPending, startTransition] = useTransition();

const submitAction = async () => {
function submitAction() {
startTransition(async () => {
const {error} = await updateName(name);
// State updates after await aren't automatically marked as Transitions,
// so wrap them in another startTransition.
startTransition(() => {
if (error) {
setError(error);
} else {
setError(error);
if (!error) {
setName('');
}
});
})
});
}

return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
<input
type="text"
name="name"
value={name}
onChange={event => setName(event.target.value)}
disabled={isPending}
/>
{error && <span>Failed: {error}</span>}
</form>
)
);
}
```

This allows you to access the `isPending` state of the Server Function by wrapping it in an Action on the client.

For more, see the docs for [Calling a Server Function outside of `<form>`](/reference/rsc/use-server#calling-a-server-function-outside-of-form)
For more, see the docs for [Calling a Server Function outside of `<form>`](/reference/rsc/use-server#calling-a-server-function-outside-of-form).

### Server Functions with Form Actions {/*using-server-functions-with-form-actions*/}
### Passing a Server Function to the `<form>` `action` prop {/*using-server-functions-with-form-actions*/}

Server Functions work with the new Form features in React 19.

You can pass a Server Function to a Form to automatically submit the form to the server:
Pass a Server Function to the `<form>` `action` prop to submit the form to the server. React passes the submitted [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) to the Server Function as its first argument:

```js [[1, 4, "updateName"]]
// actions.js
"use server";

export async function updateName(formData) {
const name = formData.get('name');
if (typeof name !== 'string' || !name) {
throw new Error('Name is required');
}
await db.users.updateName(name);
}
```

```js [[1, 3, "updateName"], [1, 7, "updateName"]]
```js [[1, 4, "updateName"], [1, 8, "updateName"]]
// UpdateName.js
"use client";

import {updateName} from './actions';
Expand All @@ -166,50 +191,68 @@ function UpdateName() {
<form action={updateName}>
<input type="text" name="name" />
</form>
)
);
}
```

When the Form submission succeeds, React will automatically reset the form. You can add `useActionState` to access the pending state, last response, or to support progressive enhancement.
When the Server Function passed to the `<form>` `action` prop succeeds, React automatically resets the form's uncontrolled fields. Users can submit the form before its JavaScript bundle loads. Use `useActionState` to access the Action's pending state and most recent return value.

For more, see the docs for [Server Functions in Forms](/reference/rsc/use-server#server-functions-in-forms).

### Server Functions with `useActionState` {/*server-functions-with-use-action-state*/}
### Calling a Server Function with `useActionState` {/*server-functions-with-use-action-state*/}

Call a Server Function with `useActionState` to access the Action's pending state and most recent return value. The Server Function receives the previous state as its first argument and the submitted [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) as its second argument. Its return value becomes the next state:

```js [[1, 4, "updateName"]]
// actions.js
"use server";

You can call Server Functions with `useActionState` for the common case where you just need access to the action pending state and last returned response:
export async function updateName(previousState, formData) {
const name = formData.get('name');
if (typeof name !== 'string' || !name) {
return {error: 'Name is required'};
}
await db.users.updateName(name);
return {error: null};
}
```

```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "submitAction"], [2, 9, "submitAction"]]
```js [[1, 5, "updateName"], [1, 8, "updateName"], [2, 8, "submitAction"], [2, 11, "submitAction"]]
// UpdateName.js
"use client";

import {useActionState} from 'react';
import {updateName} from './actions';

function UpdateName() {
const [state, submitAction, isPending] = useActionState(updateName, {error: null});

return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
<input type="text" name="name" disabled={isPending} />
{state.error && <span>Failed: {state.error}</span>}
</form>
);
}
```

When using `useActionState` with Server Functions, React will also automatically replay form submissions entered before hydration finishes. This means users can interact with your app even before the app has hydrated.
When the function passed to `useActionState` is a Server Function, users can submit the form before hydration finishes. React can display the Server Function's return value before JavaScript loads.

For more, see the docs for [`useActionState`](/reference/react/useActionState).

### Progressive enhancement with `useActionState` {/*progressive-enhancement-with-useactionstate*/}
### Supporting progressive enhancement with `useActionState` {/*progressive-enhancement-with-useactionstate*/}

Server Functions also support progressive enhancement with the third argument of `useActionState`.

```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "/name/update"], [3, 6, "submitAction"], [3, 9, "submitAction"]]
```js [[1, 5, "updateName"], [1, 8, "updateName"], [2, 8, "/name/update"], [3, 8, "submitAction"], [3, 11, "submitAction"]]
// UpdateName.js
"use client";

import {useActionState} from 'react';
import {updateName} from './actions';

function UpdateName() {
const [, submitAction] = useActionState(updateName, null, `/name/update`);
const [, submitAction] = useActionState(updateName, {error: null}, `/name/update`);

return (
<form action={submitAction}>
Expand All @@ -219,6 +262,6 @@ function UpdateName() {
}
```

When the <CodeStep step={2}>permalink</CodeStep> is provided to `useActionState`, React will redirect to the provided URL if the form is submitted before the JavaScript bundle loads.
If you pass the <CodeStep step={2}>`permalink`</CodeStep> to `useActionState`, the browser navigates to that URL when the form is submitted before the JavaScript bundle loads. At the destination, render the same form component with the same Server Function and `permalink` so React can pass the returned state to it.

For more, see the docs for [`useActionState`](/reference/react/useActionState).
Loading