@samitouri / QOS-React / commits / 967d46c76c

Add error boundary to Flight fixture (#26695)

Errors in form actions are now rethrown during render (#26689), so we can handle them using an error boundary.

Andrew Clark committed Apr 21, 2023 at 14:23 UTC 967d46c76cf9f7f35cf659a6a47c9ad456c685a8
3 files changed +54 -32
fixtures/flight/src/Button.js
+20 -17
@@ -1,27 +1,30 @@
1 'use client';
2
3 import * as React from 'react';
4 +import {flushSync} from 'react-dom';
5 +import ErrorBoundary from './ErrorBoundary.js';
6
7 export default function Button({action, children}) {
8 const [isPending, setIsPending] = React.useState(false);
9
10 return (
9 - <form>
10 - <button
11 - disabled={isPending}
12 - formAction={async () => {
13 - setIsPending(true);
14 - try {
15 - const result = await action();
16 - console.log(result);
17 - } catch (error) {
18 - console.error(error);
19 - } finally {
20 - setIsPending(false);
21 - }
22 - }}>
23 - {children}
24 - </button>
25 - </form>
11 + <ErrorBoundary>
12 + <form>
13 + <button
14 + disabled={isPending}
15 + formAction={async () => {
16 + // TODO: Migrate to useFormPending once that exists
17 + flushSync(() => setIsPending(true));
18 + try {
19 + const result = await action();
20 + console.log(result);
21 + } finally {
22 + React.startTransition(() => setIsPending(false));
23 + }
24 + }}>
25 + {children}
26 + </button>
27 + </form>
28 + </ErrorBoundary>
29 );
30 }
fixtures/flight/src/ErrorBoundary.js new
+16
@@ -0,0 +1,16 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +
5 +export default class ErrorBoundary extends React.Component {
6 + state = {error: null};
7 + static getDerivedStateFromError(error) {
8 + return {error};
9 + }
10 + render() {
11 + if (this.state.error) {
12 + return <div>Caught an error: {this.state.error.message}</div>;
13 + }
14 + return this.props.children;
15 + }
16 +}
fixtures/flight/src/Form.js
+18 -15
@@ -1,25 +1,28 @@
1 'use client';
2
3 import * as React from 'react';
4 +import {flushSync} from 'react-dom';
5 +import ErrorBoundary from './ErrorBoundary.js';
6
7 export default function Form({action, children}) {
8 const [isPending, setIsPending] = React.useState(false);
9
10 return (
9 - <form
10 - action={async formData => {
11 - setIsPending(true);
12 - try {
13 - const result = await action(formData);
14 - alert(result);
15 - } catch (error) {
16 - console.error(error);
17 - } finally {
18 - setIsPending(false);
19 - }
20 - }}>
21 - <input name="name" />
22 - <button>Say Hi</button>
23 - </form>
11 + <ErrorBoundary>
12 + <form
13 + action={async formData => {
14 + // TODO: Migrate to useFormPending once that exists
15 + flushSync(() => setIsPending(true));
16 + try {
17 + const result = await action(formData);
18 + alert(result);
19 + } finally {
20 + React.startTransition(() => setIsPending(false));
21 + }
22 + }}>
23 + <input name="name" />
24 + <button>Say Hi</button>
25 + </form>
26 + </ErrorBoundary>
27 );
28 }