0.1.0 • Published 1 year ago

fractal-form v0.1.0

Weekly downloads
-
License
-
Repository
github
Last release
1 year ago

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-form

Usage

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.

  • 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

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.

  • 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

  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

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.

0.1.0

1 year ago