Skip to content
This repository has been archived by the owner on Aug 23, 2022. It is now read-only.

Releases: davidkpiano/react-redux-form

React Redux Form v0.8.0

06 Mar 03:09
Compare
Choose a tag to compare

New Actions

Version 0.8 includes a few new helpful actions:

  • resetValidity(model) and resetErrors(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 the errorValidators, 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).

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 and createFormReducer have been renamed to modelReducer and formReducer, respectively.
  • The formReducer(...) function now takes a second argument: the initialState 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

01 Mar 03:35
Compare
Choose a tag to compare

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 the validators on every change of its model, and will only validate fields that have been changed.
  • <Form onSubmit={...}> works like the standard onSubmit 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.

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:

  1. Set the form's .pending state to true
  2. Then it'll wait for the promise to resolve.
  3. Once the promise resolves, .pending will be set to false
  • 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 to true.

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

21 Feb 19:54
Compare
Choose a tag to compare
  • Added support for custom component wrappers in <Field component={...}>: 48123c0
  • Automatic wrapping of <Field> in a <div> if className="..." 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

19 Feb 13:42
Compare
Choose a tag to compare

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!

v0.3.5

31 Jan 03:32
Compare
Choose a tag to compare
  • Using icepick to take advantage of structural sharing for frozen objects (i.e. similar concept to Immutable.js) for pure-render performance benefits (Thanks, @jihchi!)
  • Ensuring that model reducers and form reducers can operate at all levels/depths of state