UNPKG

4.15 kB Markdown View Raw
1---
2title: Actions
3order: 6
4---
5
6# Actions
7
8[MODES: framework]
9
10## Introduction
11
12Data mutations are done through Route actions. When the action completes, all loader data on the page is revalidated to keep your UI in sync with the data without writing any code to do it.
13
14Route actions defined with `action` are only called on the server while actions defined with `clientAction` are run in the browser.
15
16## Client Actions
17
18Client actions only run in the browser and take priority over a server action when both are defined.
19
20```tsx filename=app/project.tsx
21// route('/projects/:projectId', './project.tsx')
22import type { Route } from "./+types/project";
23import { Form } from "react-router";
24import { someApi } from "./api";
25
26export async function clientAction({
27 request,
28}: Route.ClientActionArgs) {
29 let formData = await request.formData();
30 let title = formData.get("title");
31 let project = await someApi.updateProject({ title });
32 return project;
33}
34
35export default function Project({
36 actionData,
37}: Route.ComponentProps) {
38 return (
39 <div>
40 <h1>Project</h1>
41 <Form method="post">
42 <input type="text" name="title" />
43 <button type="submit">Submit</button>
44 </Form>
45 {actionData ? (
46 <p>{actionData.title} updated</p>
47 ) : null}
48 </div>
49 );
50}
51```
52
53## Server Actions
54
55Server actions only run on the server and are removed from client bundles.
56
57```tsx filename=app/project.tsx
58// route('/projects/:projectId', './project.tsx')
59import type { Route } from "./+types/project";
60import { Form } from "react-router";
61import { fakeDb } from "../db";
62
63export async function action({
64 request,
65}: Route.ActionArgs) {
66 let formData = await request.formData();
67 let title = formData.get("title");
68 let project = await fakeDb.updateProject({ title });
69 return project;
70}
71
72export default function Project({
73 actionData,
74}: Route.ComponentProps) {
75 return (
76 <div>
77 <h1>Project</h1>
78 <Form method="post">
79 <input type="text" name="title" />
80 <button type="submit">Submit</button>
81 </Form>
82 {actionData ? (
83 <p>{actionData.title} updated</p>
84 ) : null}
85 </div>
86 );
87}
88```
89
90## Calling Actions
91
92Actions are called declaratively through `<Form>` and imperatively through `useSubmit` (or `<fetcher.Form>` and `fetcher.submit`) by referencing the route's path and a "post" method.
93
94### Calling actions with a Form
95
96```tsx
97import { Form } from "react-router";
98
99function SomeComponent() {
100 return (
101 <Form action="/projects/123" method="post">
102 <input type="text" name="title" />
103 <button type="submit">Submit</button>
104 </Form>
105 );
106}
107```
108
109This will cause a navigation and a new entry will be added to the browser history.
110
111### Calling actions with useSubmit
112
113You can submit form data to an action imperatively with `useSubmit`.
114
115```tsx
116import { useCallback } from "react";
117import { useSubmit } from "react-router";
118import { useFakeTimer } from "fake-lib";
119
120function useQuizTimer() {
121 let submit = useSubmit();
122
123 let cb = useCallback(() => {
124 submit(
125 { quizTimedOut: true },
126 { action: "/end-quiz", method: "post" },
127 );
128 }, []);
129
130 let tenMinutes = 10 * 60 * 1000;
131 useFakeTimer(tenMinutes, cb);
132}
133```
134
135This will cause a navigation and a new entry will be added to the browser history.
136
137### Calling actions with a fetcher
138
139Fetchers allow you to submit data to actions (and loaders) without causing a navigation (no new entries in the browser history).
140
141```tsx
142import { useFetcher } from "react-router";
143
144function Task() {
145 let fetcher = useFetcher();
146 let busy = fetcher.state !== "idle";
147
148 return (
149 <fetcher.Form method="post" action="/update-task/123">
150 <input type="text" name="title" />
151 <button type="submit">
152 {busy ? "Saving..." : "Save"}
153 </button>
154 </fetcher.Form>
155 );
156}
157```
158
159They also have the imperative `submit` method.
160
161```tsx
162fetcher.submit(
163 { title: "New Title" },
164 { action: "/update-task/123", method: "post" },
165);
166```
167
168See the [Using Fetchers][fetchers] guide for more information.
169
170---
171
172Next: [Navigating](./navigating)
173
174[fetchers]: ../../how-to/fetchers