Redux Freeform

Redux Freeform

  • GitHub

›Getting Started

Getting Started

  • Intro
  • Getting Started
  • createFormState
  • Validators
  • Constraints

API Reference

  • Validators

Getting Started

Installation

Run the following with yarn:

yarn add redux-freeform

or with npm:

npm install redux-freeform

Create A Form

Create a form config object:

import { createFormState } from "redux-freeform";

const formConfig = {
  field1: {},
  field2: {}
};

const { reducer, mapStateToProps, mapDispatchToProps } = createFormState(
  formConfig
);

Now you can use reducer, mapStateToProps, mapDispatchToProps as you would in any other Redux app.

mapStateToProps is an function for use with react-redux that takes the form state and returns an object

{
  fields: state
}

mapDispatchToProps takes a dispatch function and returns an object like so:

{
  actions: {
    fields: {
      field1: { 
        set: String -> (),
        addValidator: Object -> ()
       },
      field2: { 
        set: String -> (),
        addValidator: Object -> ()
      }
    },
    form: {
      clear: () -> ()
    }
  }
}

Note that even if fields represent numbers the set functions take strings and the coercion is handled in the state by validators and constraints.

Example usage:

const props = mapDispatchToProps(dispatch);
props.actions.fields.field1.set("foo");
props.actions.fields.fields.addValidator(hasLength(3, 4))
props.actions.form.clear();

Updating a form

When using these actions for a form or field actions inside useEffect, you will need to include the form or field actions as a dependency to avoid useEffect causing an infinite render loop.

Examples:

For field actions, include actions.fields.<fieldname>

  useEffect(() => {
    if(requiresEmail) {
      actions.fields.email.addValidator(required());
    }
  }, [actions.fields.email]);
  useEffect(() => {
    if(emailIsNotRequired) {
      actions.fields.email.removeValidator(required());
    }
  }, [actions.fields.email]);

For form actions, include actions.form

  useEffect(() => {
    if(clearOnDismount) {
      actions.form.clearValidators();
    }
  }, [actions.form]);

Putting It Together With React

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { createFormState, required, hasLength } from "redux-freeform";

const myFormConfig = {
  field1: {
    validators: [required()]
  }
};
const { reducer, mapStateToProps, mapDispatchToProps } = createFormState(
  myFormConfig
);

const MyForm = ({ actions, fields }) => (
  <div>
    {fields.field1.hasErrors && fields.field1.errors.includes(required.error)
      ? "Field 1 is required"
      : "Field 1"}
    <input
      value={fields.field1.rawValue}
      onChange={evt => actions.fields.field1.set(evt.target.value)}
      type="text"
    />
  </div>
);

const MySecondForm = ({ actions, fields, isTrue }) => {
  useEffect(() => {
    if(isTrue) {
      actions.fields.field1.addValidator(hasLength(3, 4))
    }
  }, [actions.fields.field1])

  return (
    <div>
      {fields.field1.hasErrors && fields.field1.errors.includes(required.error)
        ? "Field 1 is required"
        : fields.field1.hasErrors && fields.field1.errors.includes(hasLength.error) 
        ? "Field 1 is incorrect length" 
        : "Field 1"}
      <input
        value={fields.field1.rawValue}
        onChange={evt => actions.fields.field1.set(evt.target.value)}
        type="text"
      />
    </div>
  )
}

const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
const rootEl = document.getElementById("root");
const render = () =>
  ReactDOM.render(
    <MyForm
      {...mapStateToProps(store.getState())}
      {...mapDispatchToProps(store.dispatch)}
    />,
    rootEl
  );

render();
store.subscribe(render);
Last updated on 2/5/2025
← IntrocreateFormState →
  • Installation
  • Create A Form
  • Updating a form
    • Examples:
  • Putting It Together With React
Made with 💖 by Citybase.