Skip to content

Commit 230c2a0

Browse files
authored
docs: include example of React.lazy for tree-shaking (#1198)
1 parent 8105638 commit 230c2a0

File tree

5 files changed

+103
-32
lines changed

5 files changed

+103
-32
lines changed

docs/framework/react/guides/form-composition.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,73 @@ const ChildForm = withForm({
237237
})
238238
```
239239

240+
# Tree-shaking form and field components
241+
242+
While the above examples are great for getting started, they're not ideal for certain use-cases where you might have hundreds of form and field components.
243+
In particular, you may not want to include all of your form and field components in the bundle of every file that uses your form hook.
244+
245+
To solve this, you can mix the `createFormHook` TanStack API with the React `lazy` and `Suspense` components:
246+
247+
```typescript
248+
// src/hooks/form-context.ts
249+
import { createFormHookContexts } from '@tanstack/react-form'
250+
251+
export const { fieldContext, useFieldContext, formContext, useFormContext } =
252+
createFormHookContexts()
253+
```
254+
255+
```tsx
256+
// src/components/text-field.tsx
257+
import { useFieldContext } from '../hooks/form-context.tsx'
258+
259+
export default function TextField({ label }: { label: string }) {
260+
const field = useFieldContext<string>()
261+
262+
return (
263+
<label>
264+
<div>{label}</div>
265+
<input
266+
value={field.state.value}
267+
onChange={(e) => field.handleChange(e.target.value)}
268+
/>
269+
</label>
270+
)
271+
}
272+
```
273+
274+
```tsx
275+
// src/hooks/form.ts
276+
import {lazy} from 'react'
277+
import {createFormHook} from '@tanstack/react-form'
278+
279+
const TextField = lazy(() => import('../components/text-fields.tsx'))
280+
281+
const { useAppForm, withForm } = createFormHook({
282+
fieldContext,
283+
formContext,
284+
fieldComponents: {
285+
TextField
286+
},
287+
formComponents: {},
288+
})
289+
```
290+
291+
```tsx
292+
// src/App.tsx
293+
import { Suspense } from 'react'
294+
import { PeoplePage } from './features/people/page.tsx'
295+
296+
export default function App() {
297+
return (
298+
<Suspense fallback={<p>Loading...</p>}>
299+
<PeopleForm />
300+
</Suspense>
301+
)
302+
}
303+
```
304+
305+
This will show the Suspense fallback while the `TextField` component is being loaded, and then render the form once it's loaded.
306+
240307
# Putting it all together
241308

242309
Now that we've covered the basics of creating custom form hooks, let's put it all together in a single example.

examples/react/large-form/src/App.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { Suspense } from 'react'
12
import { PeoplePage } from './features/people/page.tsx'
23

34
export default function App() {
45
return (
5-
<div>
6+
<Suspense fallback={<p>Loading...</p>}>
67
<PeoplePage />
7-
</div>
8+
</Suspense>
89
)
910
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useStore } from '@tanstack/react-form'
2+
import { useFieldContext } from '../hooks/form-context.tsx'
3+
4+
export default function TextField({ label }: { label: string }) {
5+
const field = useFieldContext<string>()
6+
7+
const errors = useStore(field.store, (state) => state.meta.errors)
8+
9+
return (
10+
<div>
11+
<label>
12+
<div>{label}</div>
13+
<input
14+
value={field.state.value}
15+
onChange={(e) => field.handleChange(e.target.value)}
16+
/>
17+
</label>
18+
{errors.map((error: string) => (
19+
<div key={error} style={{ color: 'red' }}>
20+
{error}
21+
</div>
22+
))}
23+
</div>
24+
)
25+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { createFormHookContexts } from '@tanstack/react-form'
2+
3+
export const { fieldContext, useFieldContext, formContext, useFormContext } =
4+
createFormHookContexts()

examples/react/large-form/src/hooks/form.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,8 @@
1-
import {
2-
createFormHook,
3-
createFormHookContexts,
4-
useStore,
5-
} from '@tanstack/react-form'
1+
import { createFormHook } from '@tanstack/react-form'
2+
import { lazy } from 'react'
3+
import { fieldContext, formContext, useFormContext } from './form-context.tsx'
64

7-
const { fieldContext, useFieldContext, formContext, useFormContext } =
8-
createFormHookContexts()
9-
10-
function TextField({ label }: { label: string }) {
11-
const field = useFieldContext<string>()
12-
13-
const errors = useStore(field.store, (state) => state.meta.errors)
14-
15-
return (
16-
<div>
17-
<label>
18-
<div>{label}</div>
19-
<input
20-
value={field.state.value}
21-
onChange={(e) => field.handleChange(e.target.value)}
22-
/>
23-
</label>
24-
{errors.map((error: string) => (
25-
<div key={error} style={{ color: 'red' }}>
26-
{error}
27-
</div>
28-
))}
29-
</div>
30-
)
31-
}
5+
const TextField = lazy(() => import('../components/text-fields.tsx'))
326

337
function SubscribeButton({ label }: { label: string }) {
348
const form = useFormContext()

0 commit comments

Comments
 (0)