Skip to content

Commit 3c00e80

Browse files
authored
feat: docs reference (#21)
1 parent be6515c commit 3c00e80

File tree

1 file changed

+2
-236
lines changed

1 file changed

+2
-236
lines changed

README.md

Lines changed: 2 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
<p align="center">
2020
<a href="https://codesandbox.io/p/sandbox/headless-river-3s693c">CodeSandbox</a> |
21-
<a href="https://github.com/react-hook-form/lenses/tree/main/examples/stories">Examples</a>
21+
<a href="https://github.com/react-hook-form/lenses/tree/main/examples/stories">Examples</a> |
22+
<a href="https://react-hook-form.com/docs/uselens">Docs</a>
2223
</p>
2324

2425
## React Hook Form Lenses
@@ -31,16 +32,6 @@ React Hook Form Lenses is a powerful TypeScript-first library that brings the el
3132
npm install @hookform/lenses
3233
```
3334

34-
### Features
35-
36-
- **Type-Safe Form State**: Focus on specific parts of your form state with full TypeScript support and precise type inference
37-
- **Functional Lenses**: Build complex form state transformations through composable lens operations
38-
- **Deep Structure Support**: Handle deeply nested structures and arrays elegantly with specialized array operations
39-
- **Seamless Integration**: Work smoothly with React Hook Form's Control API and existing functionality
40-
- **Optimized Performance**: Each lens is cached and reused for optimal performance
41-
- **Array Handling**: Specialized support for array fields with type-safe mapping
42-
- **Composable API**: Build complex form state transformations through lens composition
43-
4435
### Quickstart
4536

4637
```tsx
@@ -102,228 +93,3 @@ function StringInput({ lens }: { lens: Lens<string> }) {
10293
return <input {...lens.interop((ctrl, name) => ctrl.register(name))} />;
10394
}
10495
```
105-
106-
### API Reference
107-
108-
#### Core Types
109-
110-
##### `Lens<T>`
111-
112-
The main lens type that provides operations based on the field type
113-
114-
```ts
115-
type LensWithArray = Lens<string[]>;
116-
type LensWithObject = Lens<{ name: string; age: number }>;
117-
type LensWithPrimitive = Lens<string>;
118-
```
119-
120-
#### Hooks
121-
122-
##### `useLens`
123-
124-
Creates a new lens instance
125-
126-
```tsx
127-
const lens = useLens({
128-
control: form.control, // React Hook Form control
129-
});
130-
```
131-
132-
You can also pass dependencies to clear lenses with caches and re-create all of them
133-
134-
```tsx
135-
const lens = useLens(
136-
{
137-
control: form.control, // React Hook Form control
138-
},
139-
[dependencies], // optional dependency array if you need to clear caches
140-
);
141-
```
142-
143-
#### Lens Operations
144-
145-
##### `focus`
146-
147-
Creates a new lens focused on a specific path
148-
149-
```tsx
150-
// Type-safe path focusing
151-
const profileLens = lens.focus('profile');
152-
const emailLens = lens.focus('profile.contact.email');
153-
const arrayItemLens = lens.focus('array.0');
154-
```
155-
156-
##### `reflect`
157-
158-
Transforms the lens structure with type inference.
159-
It is useful when you want to create a new lens from existing one with different shape to pass it to a shared component.
160-
161-
The first argument is a dictionary of lenses. The second argument is the original lens.
162-
163-
```tsx
164-
const contactLens = lens.reflect(({ profile }) => ({
165-
name: profile.focus('contact.firstName'),
166-
phoneNumber: profile.focus('contact.phone'),
167-
}));
168-
169-
<SharedComponent lens={contactLens} />;
170-
171-
function SharedComponent({ lens }: { lens: Lens<{ name: string; phoneNumber: string }> }) {
172-
// ...
173-
}
174-
```
175-
176-
```tsx
177-
const contactLens = lens.reflect((_, l) => ({
178-
name: l.focus('profile.contact.firstName'),
179-
phoneNumber: l.focus('profile.contact.phone'),
180-
}));
181-
182-
<SharedComponent lens={contactLens} />;
183-
184-
function SharedComponent({ lens }: { lens: Lens<{ name: string; phoneNumber: string }> }) {
185-
// ...
186-
}
187-
```
188-
189-
Also, you can restructure array lens:
190-
191-
```tsx
192-
function ArrayComponent({ lens }: { lens: Lens<{ value: string }[]> }) {
193-
return <AnotherComponent lens={lens.reflect((_, l) => [{ data: l.focus('value') }])} />;
194-
}
195-
196-
function AnotherComponent({ lens }: { lens: Lens<{ data: string }[]> }) {
197-
// ...
198-
}
199-
```
200-
201-
Pay attention that in case of array reflecting you have to pass an array with single item.
202-
203-
In addition you can use `reflect` to merge two lenses into one.
204-
205-
```tsx
206-
function Component({ lensA, lensB }: { lensA: Lens<{ firstName: string }>; lensB: Lens<{ lastName: string }> }) {
207-
const combined = lensA.reflect((_, l) => ({
208-
firstName: l.focus('firstName'),
209-
lastName: lensB.focus('lastName'),
210-
}));
211-
212-
// ...
213-
}
214-
```
215-
216-
Keep in mind that is such case the passed to `reflect` function is longer pure.
217-
218-
You can use spread in reflect if you want to leave other properties as is. In runtime the first argument is just a proxy that calls `focus` on the original lens.
219-
220-
```tsx
221-
function Component({ lens }: { lens: Lens<{ firstName: string; lastName: string; age: number }> }) {
222-
return (
223-
<PersonForm
224-
lens={lens.reflect(({ firstName, lastName, ...rest }) => ({
225-
...rest,
226-
name: firstName,
227-
surname: lastName,
228-
}))}
229-
/>
230-
);
231-
}
232-
```
233-
234-
##### `map` (Array Lenses)
235-
236-
Maps over array fields with `useFieldArray` integration
237-
238-
```tsx
239-
import { useFieldArray } from '@hookform/lenses/rhf';
240-
241-
function ContactsList({ lens }: { lens: Lens<Contact[]> }) {
242-
const { fields } = useFieldArray(lens.interop());
243-
244-
return lens.map(fields, (value, l) => <ContactForm key={value.id} lens={l} />);
245-
}
246-
```
247-
248-
##### `interop`
249-
250-
The `interop` method provides integration with react-hook-form by exposing the underlying `control` and `name` properties. This allows you to connect your lens to react-hook-form's control API.
251-
252-
The first variant involves calling `interop()` without arguments, which returns an object containing the `control` and `name` properties for react-hook-form.
253-
254-
```tsx
255-
const { control, name } = lens.interop();
256-
257-
return <input {...control.register(name)} />;
258-
```
259-
260-
The second variant is passing a callback function to `interop` which receives the `control` and `name` properties as arguments. This allows you to work with these properties directly within the callback scope.
261-
262-
```tsx
263-
return (
264-
<form onSubmit={handleSubmit(console.log)}>
265-
<input {...lens.interop((ctrl, name) => ctrl.register(name))} />
266-
<input type="submit" />
267-
</form>
268-
);
269-
```
270-
271-
The `interop` method's return value can be passed directly to the `useController` hook from react-hook-form, providing seamless integration
272-
273-
```tsx
274-
const { field, fieldState } = useController(lens.interop());
275-
276-
return (
277-
<div>
278-
<input {...field} />
279-
<p>{fieldState.error?.message}</p>
280-
</div>
281-
);
282-
```
283-
284-
### Caching System
285-
286-
All the lenses are cached to prevent component re-renders when utilizing `React.memo`.
287-
It means that focusing the same path multiple times will not create new lens instance.
288-
289-
```tsx
290-
assert(lens.focus('firstName') === lens.focus('firstName'));
291-
```
292-
293-
However, there are some difficulties when you use functions, i.e. in `reflect`
294-
295-
```tsx
296-
lens.reflect((l) => l.focus('firstName')))
297-
```
298-
299-
To make the caching work, you need to memoize the function you pass
300-
301-
```tsx
302-
lens.reflect(useCallback((l) => l.focus('firstName'), []));
303-
```
304-
305-
Here is the case where [React Compiler](https://react.dev/learn/react-compiler) can be extremely helpful. Because the function you pass to `reflect` has no side effects, react compiler will hoist it to module scope and thus lens cache will work as expected.
306-
307-
### Advanced Usage
308-
309-
#### Manual Lens Creation
310-
311-
You can create lenses manually without `useLens` hook by utilizing the `LensCore` class:
312-
313-
```tsx
314-
import { useMemo } from 'react';
315-
import { useForm } from 'react-hook-form';
316-
import { LensCore, LensesStorage } from '@hookform/lenses';
317-
318-
function App() {
319-
const { control } = useForm<{ firstName: string; lastName: string }>();
320-
321-
const lens = useMemo(() => {
322-
const cache = new LensesStorage(control);
323-
return LensCore.create(control, cache);
324-
}, [control]);
325-
326-
lens.focus('firstName');
327-
lens.focus('lastName');
328-
}
329-
```

0 commit comments

Comments
 (0)