Releases: davidkpiano/react-redux-form
React Redux Form v0.8.0
New Actions
Version 0.8 includes a few new helpful actions:
resetValidity(model)
andresetErrors(model)
can be dispatched to reset the validity and errors of any model at any time.validateErrors(model, errorValidators)
can be dispatched to validate (and set) the errors of a model based on theerrorValidators
, which are functions or a keyed object with error validator functions.- This works much in the same way that
validate(model, validators)
works, but validates that an error exists (i.e. the inverse action).
- This works much in the same way that
New Props
<Field errors={{...}}>
and<Form errors={{...}}>
can be used to specify an error validation function or keyed object with error validator functions for validation. This is especially useful when you want to hard-code error messages inside your components (of course, hard-coding is not recommended).
<Field model="user.email"
errors={{
invalid: (val) => !isEmail(val) && 'Email is invalid.'
}}
>
Enhancements
createModelReducer
andcreateFormReducer
have been renamed tomodelReducer
andformReducer
, respectively.- The
formReducer(...)
function now takes a second argument: theinitialState
of the model. This lets the form reducer know:- what fields should be initialized in the form state, and
- what the initial values are of each model, in the
.initialValue
prop of the field state.
const initialUserState = {
email: ''
};
const reducer = combineReducers({
- user: createModelReducer('user', initialUserState),
- userForm: createFormReducer('user'),
+ user: modelReducer('user', initialUserState),
+ userForm: formReducer('user', initialUserState),
});
// in a connected component render() method:
- { getField(userForm, 'email').valid && <div>Email invalid</div> }
+ { userForm.fields.email.valid && <div>Email invalid</div> }
Bug Fixes
- The
setTouched(...)
action now sets the form state to touched (Thanks @lasergoat: #44) - Validation for
<Field>
components now always happens immediately when the form is loaded. This fixes the assumption that new forms are always valid; as this is seldom the case.
React Redux Form v0.7.0
The <Form>
Component
React Redux Form 0.7.0 introduces the <Form>
component, which will allow you to provide form-wide (and per-field) validation on submit, and/or on field changes.
<Form validators={{...}}>
lets you specify validators for each field in the model, or for the form itself<Form validateOn="change">
will execute thevalidators
on every change of its model, and will only validate fields that have been changed.<Form onSubmit={...}>
works like the standardonSubmit
prop, with these two changes:- Event bubbling is prevented by default (
e.preventDefault()
) so the form doesn't auto-submit - The
onSubmit
function will not be called if the form is invalid.
- Event bubbling is prevented by default (
Here's an example of <Form>
in action:
import { Form, Field } from 'react-redux-form';
import validator from 'validator'; // Use any validation library!
// an action thunk creator
function customSubmitUser(user) {
return (dispatch) => {
// do any async submitting stuff here
}
}
// inside component render():
<Form model="user"
onSubmit={ customSubmitUser }
validators={{
// form validation
'': {
passwordsMatch: (user) => user.password === user.confirmPassword
},
// field validation
'email': {
valid: validator.isEmail,
required: (email) => email && email.length
},
'password': (pass) => pass && pass.length > 8
}}
>
<Field model="user.email">
<input type="email" />
</Field>
<Field model="user.password">
<input type="password" />
</Field>
<Field model="user.confirmPassword">
<input type="password" />
</Field>
</Form>
Custom Error Messages
Now, RRF will let you set custom error messages using actions.setErrors(model, errors)
:
import { actions, getField } from 'react-redux-form';
// in a connected component's render() method:
dispatch(actions.setErrors('user.email', 'Invalid email!'));
getField(userForm, 'email').errors;
// => 'Invalid email!'
getField(userForm, 'email').valid;
// => false
// objects and arrays, etc. can be errors, too!
dispatch(actions.setErrors('user.email', {
validEmail: 'This does not look like a valid email',
availability: 'Also this email is taken'
});
getField(userForm, 'email').errors;
// => { validEmail: 'This...', availability: 'Also, this...' } (truncated)
getField(userForm, 'email').validity;
// => { validEmail: false, availability: false }
getField(userForm, 'email').valid;
// => false
Submit via Promises with actions.submit()
The actions.submit(model, promise)
action is especially useful when you have custom error messages coming from the API:
function submitUser(user) {
return fetch(...).then(...); // sample promise
}
// somewhere with dispatch()
dispatch(actions.submit('user', submitUser(user)));
This will:
- Set the form's
.pending
state totrue
- Then it'll wait for the promise to resolve.
- Once the promise resolves,
.pending
will be set tofalse
- If the promise is rejected, the
.errors
state of the form will be set to the rejection value. - If the promise is fulfilled, the
.submitted
state will be set totrue
.
Major Clean-Up
Thanks to the huge amount of help from @chrisblossom, the RRF project was significantly cleaned up and the build optimized for size (which is an ongoing task). RRF now uses ESLint and makes use of peerDependencies
.
v0.6.1
- Added support for custom component wrappers in
<Field component={...}>
: 48123c0 - Automatic wrapping of
<Field>
in a<div>
ifclassName="..."
is specified
// Will not render a 'div' wrapper
<Field model="...">
<input />
</Field>
// Will render a 'div' wrapper because of 'className'
<Field model="..." className="field six wide">
<input />
</Field>
// Will also render a 'div' wrapper
<Field model="..." component="div">
<input />
</Field>
// Will render a View wrapper (useful for React Native)
<Field model="..." component={View}>
<input />
</Field>
React Redux Form v0.6.0
React Native Support
React Native form components are now fully supported, so you can freely use the following components with <Field>
from react-redux-form/lib/native
, without any extra configuration.
import { Field } from 'react-redux-form/lib/native';
// in your component's render() method:
<Field model="user.name">
<TextInput />
</Field>
Check out the docs on React Native and custom components for more information!
Note: You might get Warning: Failed propType
warnings when using DatePickerIOS
. This is innocuous and related to this React issue.
Immutable.js Support
If you want to use Immutable data structures in your app, or you already have existing reducers with Immutable state, you can now create Immutable model reducers or enhance existing Immutable reducers from react-redux-form/lib/immutable
:
import { createStore, combineReducers } from 'redux';
import { createModelReducer } from 'react-redux-form/lib/immutable';
import Immutable from 'immutable';
const initialUserState = Immutable.fromJS({ firstName: '', lastName: '' });
export default createStore(combineReducers({
'user': createModelReducer('user', initialUserState)
}));
import { modeled } from 'react-redux-form/immutable';
import Immutable from 'immutable';
function existingImmutableReducer(state = Immutable.Map(), action) {
// ...
}
export default modeled(existingImmutableReducer, 'existing');
Note: Make sure to provide an Immutable
initial state for every immutable reducer! This is a good practice in general.
Custom and 3rd-Party Component Support
Along with React Native, RRF now supports using createFieldClass
to create adapter <Field>
components to handle any 3rd-party component, such as react-bootstrap and material-ui:
import { createFieldClass, controls } from 'react-redux-form';
import TextField from 'material-ui/lib/text-field';
import Slider from 'material-ui/lib/slider';
import Checkbox from 'material-ui/lib/checkbox';
const MaterialField = createFieldClass({
'TextField': controls.text, // treat TextField as if it were <input type="text" />
'Slider': (props) => ({
onChange: (e, val) => props.onChange(val),
value: props.modelValue
}),
'Checkbox': (props) => ({
onCheck: (e, val) => props.onChange(val),
checked: !!props.modelValue
})
});
// in your render() method:
<MaterialField model="foo.bar">
<TextField />
</MaterialField>
Check out the docs on React Native and custom components for more information!