redux-formo
Version:
An alternate forms framework for Redux+React.
345 lines (222 loc) • 11 kB
Markdown
# redux-formo
[](https://travis-ci.org/jameslnewell/redux-formo)
An alternate forms framework for Redux+React.
## Why not `redux-form`?
- validate on blur, not change
- validate individual fields, not the whole form
## Installation
npm install --save redux-formo
## Usage
`createStore.js`
```javascript
import {createStore, applyMiddleware, combineReducers} from 'redux';
import thunk from 'redux-thunk';
import {reducer} from 'redux-formo';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
export createStoreWithMiddleware(combineReducers({
form: reducer
}));
```
`App.jsx`
```javascript
import React from 'react';
import form from 'redux-formo';
import filter from './filter';
import validate from './validate';
import submit from './submit';
class App extends React.Component {
render() {
const {
valid,
submitting,
submitted,
error,
fields: {name, phone},
onSubmit
} = this.props;
return (
<form onSubmit={onSubmit(submit)}>
{error && <p>{error}</p>}
<div>
<label>
Name: <input {...name}/>
</label>
{name.error && <p>{name.error}</p>}
</div>
<br/>
<div>
<label>
Phone: <input {...phone}/>
</label>
{phone.error && <p>{phone.error}</p>}
</div>
<br/>
<input
type="submit"
value={submitted ? 'Saved.' : (submitting ? 'Saving...' : 'Save')}
disabled={submitting || submitted}
/>
</form>
);
}
}
export default form({
name: 'personal-details',
fields: ['name', 'phone'],
filter, validate
})(App);
```
## Methods
### form(config : Object, [mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(Component)
Decorate a React Component, connecting the Redux form state and providing helper methods
for handling form and field events e.g. `onSubmit()`, `onChange()`, `onBlur()`.
#### config : Object
##### .name : String
The name of the form.
Required.
##### .fields : Array<String>
The names of the fields.
Required.
##### .defaults : Array<String>
The default values of the fields.
Optional.
##### .filter({field, value, values}) : String | Promise
A function used to filter a field value.
Optional.
Parameters:
- `field` - The name of the field being filtered
- `value` - The value of the field being filtered
- `values` - All the valid field values
Returns:
The filtered value.
##### .validate({field, value, values}) : Boolean | String | Promise
A function used to validate a field value.
Optional.
Parameters:
- `field` - The name of the field being filtered
- `value` - The value of the field being filtered
- `values` - All the valid field values
Returns:
True if the value is valid. An error string if the value is not valid.
##### .submit({dispatch, values}) : void | FSA | Promise
A function used to submit the field values.
Optional.
Parameters:
- `dispatch` - The dispatch method
- `values` - All the valid field values
Returns:
Void, a [Flux Standard Action](https://github.com/acdlite/flux-standard-action) or a Promise.
- if an error is thrown, the `error` property will be set and the form will not be marked as `submitted`
- if a FSA error is returned, the `error` property will be set and the form will not be marked as `submitted`
- if a promise is returned:
- if the promise is rejected, the `error` property will be set and the form will not be marked as `submitted`
- if the promise resolves a FSA error, the `error` property will be set and the form will not be marked as `submitted`
- in all other cases, the form will be marked as `submitted`
##### .filterOnChange : Boolean
Whether a field should be filtered when the field value changes.
Optional. Defaults to `false`.
##### .validateOnChange : Boolean
Whether a field should be validated when the field value changes.
Optional. Defaults to `false`.
##### .filterOnBlur : Boolean
Whether a field should be filtered when the field loses focus.
Optional. Defaults to `true`.
##### .validateOnBlur : Boolean
Whether a field should be validated when the field loses focus.
Optional. Defaults to `true`.
##### .filterOnSubmit : Boolean
Whether a field should be filtered when the form is submitted.
Optional. Defaults to `true`.
##### .validateOnSubmit : Boolean
Whether a field should be validated when the form is submitted.
Optional. Defaults to `true`.
##### .stateKey : String
The name of the property where the form reducer is mounted on the state.
Optional. Defaults to `form`.
##### .propKey : String
The name of the property where the form state is passed in props to the react component.
Optional. Defaults to none.
##### .destroyOnUnmount : Boolean
Whether the form state is destroyed when the component is unmounted.
Optional. Defaults to `true`.
#### mapStateToProps(state, ownProps) : Object
See the [`react-redux` documentation on the `connect` function](https://github.com/rackt/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options).
Optional.
#### mapDispatchToProps(dispatch, ownProps) : Object
See the [`react-redux` documentation on the `connect` function](https://github.com/rackt/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options).
Optional.
#### mergeProps(stateProps, dispatchProps, ownProps) : Object
See the [`react-redux` documentation on the `connect` function](https://github.com/rackt/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options).
Optional.
#### options : Object
See the [`react-redux` documentation on the `connect` function](https://github.com/rackt/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options).
Optional.
### reducer.plugin(reducers : Object) : Function
Returns a new reducer that will return a new state as a result of chaining the result of the original reducer and then
the result of the dictionary of reducers.
## Props
The decorated component will receive the following props:
- **filtering** : `bool` - whether one or more values are currently being filtered
- **validating** : `bool` - whether one or more values are currently being validated
- **submitting** : `bool` - whether the form is currently being submitted
- **submitted** : `bool` - whether the form has been submitted one or more times
- **error** : `string|undefined` - the error message from the last failed submission
- **valid** : `bool` - whether all the field values are valid
- **fields** : `object`
- **<name>** - `object`
- **name** - `string` - the name of the field
- **active** - `bool` - whether the field is currently active (i.e. focussed)
- **filtering** - `bool` - whether the filter function is currently running on the field
- **filtered** - `bool` - whether the field has been filtered one or more times since the store was created
- **validating** - `bool` - whether the validation function is currently running on the field
- **validated** - `bool` - whether the field has been validated one or more times since the store was created
- **error** - `string|undefined` - the error message from the previous validation
- **valid** - `bool` - whether the current value is valid
- **lastValidValue** `*|undefined` - the the last successfully validated value
- **value** - `*|undefined` - the current value
- **checked** - `bool|undefined` - true when the value is true, false when the value is false
- **defaultValue** - `*|undefined` - the defaultValue
- **defaultChecked** - `bool|undefined` - true when the value is true, false when the value is false
## CHANGE LOG
### v3.0.0
- *breaking change*: `filter` and `validate` actions no longer take the value(s) as parameters, but get the value(s) from the state instead
- *breaking change*: `afterValidate()` no longer receives the last valid `values`
### v2.0.1
- *fix:* `mapDispatchToProps` always returns `dispatch` so that `redux-formo` continues to work when `mapDispatchToProps` is used
### v2.0.0
- *breaking change:* Destroying the form state when the component is unmounted - set `.destroyOnUmount` to `false` to
restore the previous behaviour
- *breaking change:* In order to enable the `submit()` function to access the component props, the `submit()` function
is now passed as a parameter to the `onSubmit()` handler
- *breaking change:* Improved how initial values are set and enabled the initial values to be set from the redux state
- *breaking change:* Stopped coercing values to empty strings
- *breaking change:* Renamed `config.form` to `config.name`
- *breaking change:* Renamed `config.formPropKey` to `config.propKey`
- *breaking change:* Renamed `config.formStateKey` to `config.stateKey`
- *breaking change:* Renamed `props.fields[fieldName].validValue` to `props.fields[fieldName].lastValidValue`
- refactored internals
### v1.3.0
- added an API for hooking into the reducer
### v1.2.0
- added handling of `checkbox` inputs and custom inputs in the onChange event
### v1.1.0
- added `.filterOnChange` and `.validateOnChange` properties to allow configuration of whether validation occurs
each time the user changes the value of a field
- An un-documented function, `afterValidate()`, is called after validation of each is complete - may change in the future!
- refactored `decorate.jsx` to make it more testable
### v1.0.0
- *breaking change:* The name of the package has changed from `the-other-redux-form` to `redux-formo`
- *breaking change:* The form state is now merged into the root of your component's props unless configured by `formPropKey`
- *breaking change:* The `filter`, `validate` and `submit` methods now receive an object instead of numerous parameters
- *possible breaking change:* The `filter`, `validate` and `submit` methods receive an object containing most recent
valid values instead of the current values
- *possible breaking change:* For compatibility with packages that adhere to
[Flux Standard Action](https://github.com/acdlite/flux-standard-action) (e.g. [`redux-promise`](https://www.npmjs.com/package/redux-promise)),
if the `submit` method returns/resolves a FSA error the form submission will be assumed to have failed
- The `filter` and `validate` methods can return a promise, like the `submit` method, in order to perform asynchronous
filtration and validation
- Added unit tests for most methods
## Design decisions
- like redux-form but unlike react-redux-form, use a different subset of the state to store values (let the user choose when they want to sync/update their model with the data on the form)
## THANKS
Much of this package is inspired by the work of `@erikras` on `redux-form`. Much thanks!