You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: docs/file-conventions/route-files-v2.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -307,7 +307,7 @@ If you want one of the special characters Remix uses for these route conventions
307
307
308
308
## Folders for Organization
309
309
310
-
Routes can also be folders with a conventional node module resolution `index.tsx` file inside defining the route module. The rest of the files in the folder will not become routes. This allows you to organize your code closer to the routes that use them instead of repeating the feature names across other folders.
310
+
Routes can also be folders with a `route.tsx` file inside defining the route module. The rest of the files in the folder will not become routes. This allows you to organize your code closer to the routes that use them instead of repeating the feature names across other folders.
311
311
312
312
<docs-info>The files inside a folder have no meaning for the route paths, the route path is completely defined by the folder name</docs-info>
Copy file name to clipboardexpand all lines: docs/guides/optimistic-ui.md
+2-2
Original file line number
Diff line number
Diff line change
@@ -11,8 +11,8 @@ Remix can help you build optimistic UI with [`useNavigation`][use-navigation] an
11
11
## Strategy
12
12
13
13
1. User submits a form (or you do with [`useSubmit`][use-submit] or [`fetcher.submit`][fetcher-submission]).
14
-
2. Remix makes the submission and its data immediately available to you on [`navigation.formData`][navigation-formdata] or [`fetcher.submission`][fetcher-submission].
15
-
3. App uses [`submission.formData`][form-data] to render an optimistic version of _what it will render_ when the submission completes successfully.
14
+
2. Remix makes the submission and its data immediately available to you on [`navigation.formData`][navigation-formdata] or [`fetcher.formData`][fetcher-submission].
15
+
3. App uses [`formData`][form-data] to render an optimistic version of _what it will render_ when the submission completes successfully.
16
16
4. Remix automatically revalidates all the data.
17
17
- If successful, the user doesn't even notice.
18
18
- If it fails, the page data is automatically in sync with the server so the UI reverts automatically.
Copy file name to clipboardexpand all lines: docs/hooks/use-fetcher.md
+59-20
Original file line number
Diff line number
Diff line change
@@ -44,8 +44,10 @@ function SomeComponent() {
44
44
45
45
// build UI with these
46
46
fetcher.state;
47
-
fetcher.type;
48
-
fetcher.submission;
47
+
fetcher.formMethod;
48
+
fetcher.formAction;
49
+
fetcher.formData;
50
+
fetcher.formEncType;
49
51
fetcher.data;
50
52
}
51
53
```
@@ -71,6 +73,8 @@ You can know the state of the fetcher with `fetcher.state`. It will be one of:
71
73
72
74
#### `fetcher.type`
73
75
76
+
<docs-error>`fetcher.type` is deprecated and will be removed in v2.</docs-error>
77
+
74
78
This is the type of state the fetcher is in. It's like `fetcher.state`, but more granular. Depending on the fetcher's state, the types can be the following:
75
79
76
80
-`state === "idle"`
@@ -89,8 +93,47 @@ This is the type of state the fetcher is in. It's like `fetcher.state`, but more
89
93
-**actionRedirect** - The action from an "actionSubmission" returned a redirect and the page is transitioning to the new location.
90
94
-**normalLoad** - A route's loader is being called without a submission (`fetcher.load()`).
91
95
96
+
##### Moving away from `fetcher.type`
97
+
98
+
The `type` field has been been deprecated and will be removed in v2. We've found that `state` is sufficient for almost all use-cases, and when it's not you can derive sub-types via `fetcher.state` and other fields. Here's a few examples:
99
+
100
+
```js
101
+
functionComponent() {
102
+
let fetcher =useFetcher();
103
+
104
+
let isDone =
105
+
fetcher.state==="idle"&&fetcher.data!=null;
106
+
107
+
let isActionSubmission =fetcher.state==="submitting";
108
+
109
+
let isActionReload =
110
+
fetcher.state==="loading"&&
111
+
fetcher.formMethod!=null&&
112
+
fetcher.formMethod!="get"&&
113
+
// If we returned data, we must be reloading
114
+
fetcher.data!=null;
115
+
116
+
let isActionRedirect =
117
+
fetcher.state==="loading"&&
118
+
fetcher.formMethod!=null&&
119
+
navigation.formMethod!="get"&&
120
+
// If we have no data we must have redirected
121
+
fetcher.data==null;
122
+
123
+
let isLoaderSubmission =
124
+
navigation.state==="loading"&&
125
+
navigation.state.formMethod==="get";
126
+
127
+
let isNormalLoad =
128
+
navigation.state==="loading"&&
129
+
navigation.state.formMethod==null;
130
+
}
131
+
```
132
+
92
133
#### `fetcher.submission`
93
134
135
+
<docs-error>`fetcher.submission` is deprecated and will be removed in v2. Instead, the fields inside of `submission` have been flattened onto the `fetcher` itself (`fetcher.formMethod`, `fetcher.formAction`, `fetcher.formData`, `fetcher.formEncType`)</docs-error>
136
+
94
137
When using `<fetcher.Form>` or `fetcher.submit()`, the form submission is available to build optimistic UI.
95
138
96
139
It is not available when the fetcher state is "idle" or "loading".
@@ -153,7 +196,7 @@ function SomeComponent() {
153
196
const fetcher =useFetcher();
154
197
155
198
useEffect(() => {
156
-
if (fetcher.type==="init") {
199
+
if (fetcher.state==="idle"&&fetcher.data==null) {
157
200
fetcher.load("/some/route");
158
201
}
159
202
}, [fetcher]);
@@ -204,7 +247,10 @@ function NewsletterSignup() {
204
247
const ref =useRef();
205
248
206
249
useEffect(() => {
207
-
if (newsletter.type==="done"&&newsletter.data.ok) {
250
+
if (
251
+
newsletter.state==="idle"&&
252
+
newsletter.data?.ok
253
+
) {
208
254
ref.current.reset();
209
255
}
210
256
}, [newsletter]);
@@ -225,7 +271,7 @@ function NewsletterSignup() {
225
271
</button>
226
272
</p>
227
273
228
-
{newsletter.type==="done"? (
274
+
{newsletter.state==="idle"&&newsletter.data? (
229
275
newsletter.data.ok? (
230
276
<p>Thanks for subscribing!</p>
231
277
) :newsletter.data.error? (
@@ -283,18 +329,12 @@ export function NewsletterSignup() {
283
329
Form={newsletter.Form}
284
330
data={newsletter.data}
285
331
state={newsletter.state}
286
-
type={newsletter.type}
287
332
/>
288
333
);
289
334
}
290
335
291
336
// used here and in the route
292
-
exportfunction NewsletterForm({
293
-
Form,
294
-
data,
295
-
state,
296
-
type,
297
-
}) {
337
+
exportfunction NewsletterForm({ Form, data, state }) {
298
338
// refactor a bit in here, just read from props instead of useFetcher
299
339
}
300
340
```
@@ -309,12 +349,7 @@ import { NewsletterForm } from "~/NewsletterSignup";
Copy file name to clipboardexpand all lines: docs/hooks/use-fetchers.md
+8-8
Original file line number
Diff line number
Diff line change
@@ -27,14 +27,14 @@ For example, imagine a UI where the sidebar lists projects, and the main view di
27
27
+-----------------+----------------------------┘
28
28
```
29
29
30
-
When the user clicks a checkbox, the submission goes to the action to change the state of the task. Instead of creating a "loading state" we want to create an "optimistic UI" that will **immediately** update the checkbox to appear checked even though the server hasn't processed it yet. In the checkbox component, we can use `fetcher.submission`:
30
+
When the user clicks a checkbox, the submission goes to the action to change the state of the task. Instead of creating a "loading state" we want to create an "optimistic UI" that will **immediately** update the checkbox to appear checked even though the server hasn't processed it yet. In the checkbox component, we can use `fetcher.formData`:
Copy file name to clipboardexpand all lines: docs/hooks/use-transition.md
+56-5
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,10 @@ title: useTransition
4
4
5
5
# `useTransition`
6
6
7
+
<docs-error>This API will be removed in v2 in favor of [`useNavigation`][use-navigation]. You can start using the new `useNavigation` hook today to make upgrading in the future easy, but you can keep using `useTransition` until v2.</docs-error>
8
+
9
+
---
10
+
7
11
<docs-success>Watch the <ahref="https://www.youtube.com/playlist?list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">📼 Remix Singles</a>: <ahref="https://www.youtube.com/watch?v=y4VLIFjFq8k&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Pending UI</a>, <ahref="https://www.youtube.com/watch?v=bMLej7bg5Zo&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Clearing Inputs After Form Submissions</a>, and <ahref="https://www.youtube.com/watch?v=EdB_nj01C80&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6">Optimistic UI</a></docs-success>
8
12
9
13
This hook tells you everything you need to know about a page transition to build pending navigation indicators and optimistic UI on data mutations. Things like:
@@ -114,11 +118,62 @@ function SubmitButton() {
114
118
}
115
119
```
116
120
121
+
### Moving away from `transition.type`
122
+
123
+
The `type` field has been removed in the new `useNavigation` hook (which will replace `useTransition` in Remix v2). We've found that `state` is sufficient for almost all use-cases, and when it's not you can derive sub-types via `navigation.state` and other fields. Also note that the `loaderSubmission` type is now represented with `state: "loading"`. Here's a few examples:
124
+
125
+
```js
126
+
functionComponent() {
127
+
let navigation =useNavigation();
128
+
129
+
let isActionSubmission =
130
+
navigation.state==="submitting";
131
+
132
+
let isActionReload =
133
+
navigation.state==="loading"&&
134
+
navigation.formMethod!=null&&
135
+
navigation.formMethod!="get"&&
136
+
// We had a submission navigation and are loading the submitted location
137
+
navigation.formAction===navigation.pathname;
138
+
139
+
let isActionRedirect =
140
+
navigation.state==="loading"&&
141
+
navigation.formMethod!=null&&
142
+
navigation.formMethod!="get"&&
143
+
// We had a submission navigation and are now navigating to different location
144
+
navigation.formAction!==navigation.pathname;
145
+
146
+
let isLoaderSubmission =
147
+
navigation.state==="loading"&&
148
+
navigation.state.formMethod==="get"&&
149
+
// We had a loader submission and are navigating to the submitted location
150
+
navigation.formAction===navigation.pathname;
151
+
152
+
let isLoaderSubmissionRedirect =
153
+
navigation.state==="loading"&&
154
+
navigation.state.formMethod==="get"&&
155
+
// We had a loader submission and are navigating to a new location
156
+
navigation.formAction!==navigation.pathname;
157
+
}
158
+
```
159
+
117
160
## `transition.submission`
118
161
119
162
Any transition that started from a `<Form>` or `useSubmit` will have your form's submission attached to it. This is primarily useful to build "Optimistic UI" with the `submission.formData`[`FormData`][form-data] object.
120
163
121
-
TODO: Example
164
+
### Moving away from `transition.submission`
165
+
166
+
The `submission` field has been removed in the new `useNavigation` hook (which will replace `useTransition` in Remix v2) and the same sub-fields are now exposed directly on the `navigation`:
167
+
168
+
```js
169
+
functionComponent() {
170
+
let navigation =useNavigation();
171
+
// navigation.formMethod
172
+
// navigation.formAction
173
+
// navigation.formData
174
+
// navigation.formEncType
175
+
}
176
+
```
122
177
123
178
## `transition.location`
124
179
@@ -149,10 +204,6 @@ function PendingLink({ to, children }) {
149
204
150
205
Note that this link will not appear "pending" if a form is being submitted to the URL the link points to, because we only do this for "loading" states. The form will contain the pending UI for when the state is "submitting", once the action is complete, then the link will go pending.
151
206
152
-
## v2 deprecation
153
-
154
-
This API will be removed in v2 in favor of [`useNavigation`][use-navigation]. You can start using the new `useNavigation` hook today to make upgrading in the future easy, but you can keep using `useTransition` before v2.
Copy file name to clipboardexpand all lines: docs/route/catch-boundary.md
+4
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,8 @@ title: CatchBoundary
4
4
5
5
# `CatchBoundary`
6
6
7
+
<docs-warning>The separation of `CatchBoundary` and `ErrorBoundary` has been deprecated and Remix v2 will use a singular `ErrorBoundary` for all thrown Responses and Errors. It is recommended that you opt-into the new behavior in Remix v1 via the `future.v2_errorBoundary` flag in your `remix.config.js` file. Please refer to the [ErrorBoundary (v2)][error-boundary-v2] docs for more information.</docs-warning>
8
+
7
9
A `CatchBoundary` is a React component that renders whenever an action or loader throws a `Response`.
8
10
9
11
**Note:** We use the word "catch" to represent the codepath taken when a `Response` type is thrown; you thought about bailing from the "happy path". This is different from an uncaught error you did not expect to occur.
@@ -29,3 +31,5 @@ export function CatchBoundary() {
<docs-info>You can opt into the Remix v2 `ErrorBoundary` behavior via the `future.v2_errorBoundary` flag in your `remix.config.js`</docs-info>
8
+
9
+
If you export an `ErrorBoundary` component from your route module, it will be used as the React Router [`errorElement`][rr-error-element] and will render if you throw from a loader/action or if React throws during rendering your Route component.
0 commit comments