An open API service indexing awesome lists of open source software.

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.

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.