https://github.com/intercaetera/fractal-form
An experimental React form library using lenses.
https://github.com/intercaetera/fractal-form
Last synced: over 1 year ago
JSON representation
An experimental React form library using lenses.
- Host: GitHub
- URL: https://github.com/intercaetera/fractal-form
- Owner: intercaetera
- Created: 2023-02-02T20:44:38.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-02-02T21:02:38.000Z (over 3 years ago)
- Last Synced: 2024-08-08T18:04:27.457Z (almost 2 years ago)
- Language: JavaScript
- Size: 334 KB
- Stars: 12
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# fractal-form
An experimental React form library using lenses. Lenses are a concept from functional programming. They are modular data accessors that play nice with immutable data. A big advantage of lens implementation in this library is that they are self-similar, so you can create reusable form components at any level of nesting in your application state.
This library is heavily inspired by André Staltz's [use-profunctor-state](https://github.com/staltz/use-profunctor-state).
See `src/Example.js` for an example implementation.
## Installation
```
npm install fractal-form
```
## Usage
### Basic example
```jsx
import { memo, useState } from "react"
import { useFractalForm, useLensField } from "fractal-form"
const Input = memo(({ label, value, onChange }) => (
{label}:
))
export const Basic = () => {
const [submittedValues, setSubmittedValues] = useState({})
const {useFormLens, value} = useFractalForm({ name: '' })
const [nameField] = useLensField(useFormLens, 'name')
const submitForm = () => setSubmittedValues(value)
return (
Submit form
{JSON.stringify(submittedValues, null, 2)}
)
}
```
## API Reference
#### `useFractalForm`
```javascript
const initialValues = { name: 'Bob' }
const {
form, value, error, touched,
setForm, setValues, setErrors, setTouched,
useFormLens, useValuesLens, useErrorsLens, useTouchedLens,
} = useFractalForm(initialValues)
```
Create a form object for a given initial state.
- `form` is the entire form state, an object composed of keys `{ value, error, touched }`.
- `value` contains the form values. Initially set to `initialValues`.
- `error` contains the errors. Initially set to `{}`
- `touched` contains the touched status of the fields. Initally set to `{}`
- `set*` are functions that set the given object outright. You probably should avoid using those.
- `use*Lens` are hooks which provide lenses to each one of the properties. They are the same as `useLens` hooks returned from `useLensState` (see below).
#### `useLensField`
```javascript
const validateName = (_parentValue, name) => name.length < 5 ? "Name too short" : null
const { useFormLens } = useFractalForm({ name: 'Bob' })
const [nameField, setNameField, useNameFieldLens] = useLensField(useFormLens, 'name', validateName)
return (
)
```
This hook creates a lens that focuses on a particular field name from the `value`, `touched`, and `error` object.
- `nameField` is a utility object containing the `value`, `error`, and `touched` values for the given field name as well as `onChange` (updates the value and validates it) and `onBlur` (sets `touched` to true) callbacks.
- `setNameField` expects an object of `{ value, error, touched }` for the given field
- `useNameFieldLens` is a lens for the value, error and touched for the given field. It can be provided as the first argument to another `useLensField`
#### `useLensState`
```javascript
const [state, setState, useLens] = useLensState({ name: 'Bob' })
const [name, setName] = useLens(s => s.name, (s, a) => ({ ...s, name: a }))
console.log(state) // -> { name: 'Bob' }
console.log(name) // -> 'Bob'
setName('Alice')
console.log(name) // -> 'Alice'
console.log(state) // -> { name: 'Alice' }
setState({ name: 'Charles' })
console.log(name) // -> 'Charles'
```
This hook is exactly the same as React's `useState` except it adds another element to the array. `useLens` is a hook that takes two functions:
- `view: s => a` takes a full state `s` and returns a partial state `a`
- `update: (s, a) => t` takes a full state `s` and a new partial state `a` and returns a new full state `t`
The two states are going to be synchronised.
The lenses are memoized so most of the time wrapping a component which uses them in `React.memo` should prevent unnecessary rerenders.
#### `lensForProp`
```javascript
const [state, setState, useLens] = useLensState({ name: 'Bob' })
const [name, setName] = useLens(...lensForProp('name'))
```
A helper which takes a key name returns a pair of functions `[view, update]` for that key name.