redux-easy-forms

REForms: A React-Redux forms library for the people!

Usage no npm install needed!

<script type="module">
  import reduxEasyForms from 'https://cdn.skypack.dev/redux-easy-forms';
</script>

README

Redux Easy Forms

redux-easy-forms

See it in action: REF DEMO

Full rewrite as of ver 0.3.0 -- smaller, cleaner, nicer API :)

Yet another forms solution

  • Simplify dealing with client-side forms
  • Define your form fields via a simple "schema" object
  • Supply desired validation functions and error messages per field
  • Use a friendly API to interact with your forms and data
  • Obtain all JSX props for each input via a single API method call

Approach

REF exposes a small number of handy methods to cut down on common form-related chores. It maintains its "private" Redux state, eliminating the need for dispatching actions or connecting to the forms reducer directly. It is a fairly narrowly-focused abstraction, compatible with native HTML inputs and any React components which follow the same props (adaptable).

API Methods: clear | clearLiveErrors | get | getErrors | getLiveErrors | init | isDirty | isValid | props | restorePristine | saveAsPristine | set | setFocus

Install

npm install redux-easy-forms --save or yarn add redux-easy-forms

  1. Define forms "schema" object and a validators object for ALL forms used throughout your app:
const schema = {
  login: {                                                  // specify unique key per each form
    password: { type: 'password' },                         // unique name per input within each form
    username: { type: 'text', placeholder: 'Username' }     // specify type and any other valid props
  },
  agreement: {
    pin:  { type: 'tel', validators: 'isPin' },             // reference desired validator by key
    agree:  [{                                              // checkboxes/radios/select must be arrays
      type: 'checkbox',
      value: 'on',
      validators: 'isAgree'
    }],
    duration: [
      { type: 'select-one', value: 'day', selected: true }, // can have init value, checked, or selected
      { type: 'select-one', value: 'week' },
      { type: 'select-one', value: 'month' },
    ],
  }
};

const validators = {
  isAgree: { fn: val => !!val.length, error: 'You must agree to proceed' },
  isPin: [
    { fn: val => !!val, error: 'PIN is required' },
    { fn: val => val.length === 4, error: '4-digit PIN is required' }
  ],
}
  1. Add reformsReducer to your Redux store and wrap your app with the ReformsProvider:
import { reformsReducer, ReformsProvider } from 'redux-easy-forms';

const rootReducer = combineReducers({
  reformsData: reformsReducer                               // <-- be sure to name it reformsData
  /* ... */                                                 // <-- your other reducers...

const store = createStore(rootReducer);

<Provider store={store}>
  <ReformsProvider schema={schema} validators={validators}> // <-- beneath the Redux provider is great
    <App />
  </ReformsProvider>
</Provider>
  1. Then, for any component needing access to REForms, enhance it with the withReforms HOC:
import { withReforms } from 'redux-easy-forms';             // <--

class LoginPage extends React.Component { /* ... */ }

export default withReforms(LoginPage);                      // <--

Of course, you can also compose in connect to any of your other reducers:

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withReforms(LoginPage));                                  // <--

Or, if you enjoy using the decorator syntax:

@connect(mapStateToProps, mapDispatchToProps)
@withReforms
class LoginPage extends React.Component { /* ... */ }

Usage

The enhanced component will now receive this.props.reforms, which provides a handy API to your forms data:

const { reforms } = this.props;

To render an input field in JSX:

<input {...reforms.props('login', 'username')}/>

The props method returns all necessary props in one swoop (including name, value, onChange, etc.)

Other API examples:

reforms.setFocus('login', 'username');               // --> username input gets focused
reforms.set('login', {username: {value: 'Jane'}});   // --> 'Jane' appears in username field
reforms.get('login', 'username');                    // --> 'Jane'
reforms.get('login');                                // --> { username: 'Jane', password: '' }
reforms.isValid('login');                            // --> true

API Reference

clear(form:String, [name:String])

Clear all fields within a given form, or a single field. Also reset the "touched" status, thus clearing any "live" validation errors.

reforms.clear('login')


clearLiveErrors(form:String, [name:String])

Reset the "touched" status of specified form field(s), thus clearing any "live" validation errors.

reforms.clearLiveErrors('login')


get(form:String, [name:String]) ⇒ Object or String|Array

Get current form values (object of key-vals), or the value of a given form field (string, or an array of strings if multiple values). For multi-input arrays (checkboxes, radios, select-one) holding only one value element, it is delivered as a string.

reforms.get('login')


getErrors(form:String, [name:String]) ⇒ Object or Array

Get validation errors for the entire form, or a given form field. Errors are arrays of strings, or an empty array (if no errors).

reforms.getErrors('login')


getLiveErrors(form:String, [name:String]) ⇒ Object or String

Suitable for per-field errors while editing a form. Delivers only the first error, as long as the form/field is "touched" and not in focus.

reforms.getLiveErrors('login', 'username')


init(schema:Object)

Dynamically initialize additional form schema into REF. Existing form names will be "extended" in. Any validators referenced in the new schema must already be defined.

reforms.init({ 'note_2': { note: { type: 'text' } } })


isDirty(form:String, [name:String]) ⇒ Boolean

Check whether a form or a given field have changed from their "pristine" state. A form/field is considered "pristine" when first initialized, upon performing a set, or saveAsPristine.

reforms.isDirty('login')


isValid(form:String, [name:String]) ⇒ Boolean

Check whether a form or a given field have no validation errors.

reforms.isValid('login')


props(form:String, name:String, [value:String]) ⇒ Object

Get all JSX props for a given input field. For checkboxes and radios, the input's value is required (third argument). Returns the schema props along with REF-specific props, e.g. onChange or onClick handlers, ref (used for setFocus), plus onFocus & onBlur (to support getLiveErrors logic).

reforms.props('login', 'username') or reforms.props('login', 'agree', 'on')


restorePristine(form:String, [name:String])

Reset all form fields, or a given field, to their "pristine" state.

reforms.restorePristine('login')


saveAsPristine(form:String, [name:String])

Store current form state, or the state of a given field, as the new "pristine" state.

reforms.saveAsPristine('login')


set(form:String, payload:Object)

Set value(s) into one or more fields of a given form. The payload must match the schema structure exactly, as it will be "extended" directly over the current field data. To be bullet-proofed in future versions, in the meantime, tread lightly!

reforms.set('login', { username: { value: 'me@example.com', disabled: true } })


setFocus(form:String, name:String)

Set focus to a given field.

reforms.setFocus('login', 'username')

Changelog

See Releases