Package Exports
- redux-form
- redux-form/lib/actions
- redux-form/lib/reduxForm
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (redux-form) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
#redux-form
@reduxForm
is an ES7 decorator to for enabling a form in React to use Redux to store all of
its state.
Installation
npm install --save redux-form
Benefits
Why would anyone want to do this, you ask? React a perfectly good way of keeping state in each component! The reasons are twofold.
Hot Reloading
When used in conjunction with React Hot Loader, you can modify your components, rebuild your app and immediately see your changes without losing your form data. This may seem trivial, but the minutes of refilling out forms in a development environment really add up.
Stateless Components
By removing the state from your form components, you inherently make them easier to understand, test, and debug. The React philosophy is to always try to use props
instead of state
when possible.
How it works
When you are adding your reducers to your redux store, add a new one with createFormReducer(])
.
import { createStore, combineReducers } from 'redux';
import { createFormReducer } from 'redux-form';
const reducers = {
// ... your other reducers here ...
createFormReducer('contacts', ['name', 'address', 'phone'])
}
const reducer = combineReducers(reducers);
const store = createStore(reducer);
Then, on your form component, add the @reduxForm('contacts')
decorator.
import React, {Component, PropTypes} from 'react';
import reduxForm from 'redux-form';
import contactValidation from './contactValidation';
@reduxForm('contacts', contactValidation)
export default class ContactForm extends Component {
static propTypes = {
data: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired,
handleChange: PropTypes.func.isRequired,
showAll: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired
}
render() {
const {
data: {name, address, phone},
errors: {name: nameError, address: addressError, phone: phoneError},
handleChange
} = this.props;
return (
<form>
<label>Name</label>
<input type="text" value={name} onChange={handleChange('name')}/>
{nameError ? <div>{nameError}</div>}
<label>Address</label>
<input type="text" value={address} onChange={handleChange('address')}/>
{addressError ? <div>{addressError}</div>}
<label>Phone</label>
<input type="text" value={phone} onChange={handleChange('phone')}/>
{phoneError ? <div>{phoneError}</div>}
</form>
);
}
}
Notice that we're just using vanilla <input>
elements there is no state in the ContactForm
component. I have left handling onSubmit
as an excercise for the reader. Hint: your data is in this.props.data
.
Validation
You will need to supply your own validation function, which is in the form ({}) => {}
and takes in all your data and spits out error messages. For example:
function contactValidation(data) {
const errors = {};
if(!data.name) {
errors.name = 'Required';
}
if(data.address && data.address.length > 50) {
errors.address = 'Must be fewer than 50 characters';
}
if(!data.phone) {
errors.phone = 'Required';
} else if(!/\d{3}-\d{3}-\d{4}/.test(data.phone)) {
errors.phone = 'Phone must match the form "999-999-9999"'
}
return errors;
}
You get the idea.
API
Each form has a sliceName
. That's the key in the Redux store tree where the data will be mounted.
createFormReducer(sliceName:string, fields:Array<string>, validate:Function)
-sliceName
: string
the name of your form and the key to where your form's state will be mounted in the Redux store
- fields : Array<string>
a list of all your fields in your form.
- validation : Function
your validation function
@reduxForm(sliceName:string)
-sliceName
: string
the name of your form and the key to where your form's state will be mounted in the Redux store
props
The props passed into your decorated component will be:
-handleChange(field:string) : Function
returns a
handleChange
function for the field passed.
-showAll() : Function
marks all fields as "visited" to show errors. should be called on form submission.
-reset() : Function
clears all the values in the form
-data:Object
the form data, in the form
{ field1: <string>, field2: <string> }
-errors:Object
all the errors, in the form
{ field1: <string>, field2: <string> }
-visited:Object
the visited flags for each field, in the form
{ field1: <boolean>, field2: <boolean> }
Running Example
Check out the react-redux-universal-hot-example project to see redux-form
in action.
This is an extremely young library, so the API may change. Comments and feedback welcome.