Skip to content

Instantly share code, notes, and snippets.

@StevenLangbroek
Last active February 9, 2017 22:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StevenLangbroek/588ed16cdfe923cefd2cab9fff062950 to your computer and use it in GitHub Desktop.
Save StevenLangbroek/588ed16cdfe923cefd2cab9fff062950 to your computer and use it in GitHub Desktop.
Validation for Redux-form

"Thunked" validation in redux-form

Validation in redux-form can be approached using many "schema-validation" libraries. I used validate.js, but ran into a restriction: we needed to validate user input differently based on other input in that same form. This is quite a common requirement for validation, and was surprisingly elegant to solve in redux-form.

small caveat: not adapted for redux-form 6

Libraries used:

// A normal validate.js schema.
export default {
userName: {
presence: true
},
password: {
presence: true
},
confirmPassword: {
presence: true,
equals: 'password'
}
};
// A "thunked" schema: before validating, this function is called with the attributes of the form,
// and the resulting schema is then used to actually validate the function.
export const loginSchema = (attributes) => ({
userName: {
...defaultSchema,
...userNameSchema
},
emailAddress: {
...defaultSchema,
...emailAddressSchema
}
}[attributes.loginType])
import validate from 'validate.js';
/**
* Returns a validation function to be used in `redux-form`. If the schema
* is a function, it will be evaluated against the current attributes before
* actually validating, allowing for conditional validation.
* @param {Object} schema Validate.js schema
* @return {Function} redux-form validation function.
*/
export default (schema) => {
return (attributes) => {
const result = validate(
attributes,
typeof schema === 'function' ? schema(attributes) : schema)
);
// validate.js returns null if the form is valid, redux-form expects empty object.
return result ? flatten(result) : {};
};
};
// Validate.js outputs an array of error-messages, but we're
// only interested in 1 at a time.
const flatten = (result) => Object.keys(result).reduce((acc, key) => ({
...acc,
[key]: result[key][0],
}), {});
import React from 'react';
import { reduxForm, propTypes } from 'redux-form';
import { loginSchema, login } from 'reducers/auth';
import createValidator from 'helpers/validation';
const LoginForm = ({
fields,
handleSubmit,
login,
}) => ({
<form onSubmit={handleSubmit(login)}>
<input type="text" {...fields.userName} />
{fields.userName.touched && !!fields.userName.error && <span>{fields.userName.error}</span>}
{/* etc */}
<button type="submit">Log me in scotty!</button>
</form>
});
LoginForm.propTypes = {
...propTypes, // spread in reduxForm's propTypes
login: PropTypes.func.isRequired,
}
const mapFormToProps = {
form: 'loginForm',
fields: [
'userName',
'password',
'confirmPassword',
],
validate: createValidator(loginSchema),
}
const mapDispatchToProps = (dispatch) => ({
login: (data) => dispatch(login(data)),
});
export default reduxForm(
mapFormToProps,
null, // no state needed for this form
mapDispatchToProps,
)(LoginForm);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment