fractal-form v0.1.0
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.
See src/Example.js for an example implementation.
Installation
npm install fractal-formUsage
Basic example
import { memo, useState } from "react"
import { useFractalForm, useLensField } from "fractal-form"
const Input = memo(({ label, value, onChange }) => (
  <label>{label}:
    <input value={value} onChange={onChange} />
  </label>
))
export const Basic = () => {
  const [submittedValues, setSubmittedValues] = useState({})
  const {useFormLens, value} = useFractalForm({ name: '' })
  const [nameField] = useLensField(useFormLens, 'name')
  const submitForm = () => setSubmittedValues(value)
  
  return (
    <div>
      <Input label="Name" {...nameField} />
      <button onClick={submitForm}>Submit form</button>
      <pre>{JSON.stringify(submittedValues, null, 2)}</pre>
    </div>
  )
}API Reference
useFractalForm
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.
- formis the entire form state, an object composed of keys- { value, error, touched }.
- valuecontains the form values. Initially set to- initialValues.
- errorcontains the errors. Initially set to- {}
- touchedcontains 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*Lensare hooks which provide lenses to each one of the properties. They are the same as- useLenshooks returned from- useLensState(see below).
useLensField
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 (
  <input {...nameField} />
)This hook creates a lens that focuses on a particular field name from the value, touched, and error object.
- nameFieldis a utility object containing the- value,- error, and- touchedvalues for the given field name as well as- onChange(updates the value and validates it) and- onBlur(sets- touchedto true) callbacks.
- setNameFieldexpects an object of- { value, error, touched }for the given field
- useNameFieldLensis a lens for the value, error and touched for the given field. It can be provided as the first argument to another- useLensField
useLensState
  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 => atakes a full state- sand returns a partial state- a
- update: (s, a) => ttakes a full state- sand a new partial state- aand 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
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.
3 years ago