GithubHelp home page GithubHelp logo

gaearon / redux-form Goto Github PK

View Code? Open in Web Editor NEW

This project forked from redux-form/redux-form

7.0 2.0 1.0 252 KB

An ES7 decorator for forms using Redux and React

License: MIT License

Shell 4.49% JavaScript 95.51%

redux-form's Introduction

#redux-form

redux-form works with React Redux to enable an html 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 threefold.

Unidirectional Data Flow

For the same reason that React and Flux is superior to Angular's bidirectional data binding. Tracking down bugs is much simpler when the data all flows through one dispatcher.

Redux Dev Tools

When used in conjunction with Redux Dev Tools, you can fast forward and rewind through your form data entry to better find bugs.

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);

reduxForm() creates a Higher Order Component that expects a dispatch prop and a slice of the Redux store where its data is stored as a form prop. These should be provided by React Redux's connect() function.

Let's look at an example:

Then, on your form component, add the @reduxForm('contacts') decorator.

import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import reduxForm from 'redux-form';
import contactValidation from './contactValidation';

class ContactForm extends Component {
  // you don't need all to define all these props,
  // only the ones you intend to use
  static propTypes = {
    data: PropTypes.object.isRequired,
    dirty: PropTypes.bool.isRequired,
    errors: PropTypes.object.isRequired,
    handleBlur: PropTypes.func.isRequired,
    handleChange: PropTypes.func.isRequired,
    initializeForm: PropTypes.func.isRequired,
    invalid: PropTypes.bool.isRequired,
    pristine: PropTypes.bool.isRequired,
    resetForm: PropTypes.func.isRequired,
    touch: PropTypes.func.isRequired,
    touched: PropTypes.object.isRequired,
    touchAll: PropTypes.func.isRequired,
    untouch: PropTypes.func.isRequired,
    untouchAll: PropTypes.func.isRequired,
    valid: PropTypes.bool.isRequired
  }
  
  render() {
    const {
      data: {name, address, phone},
      errors: {name: nameError, address: addressError, phone: phoneError},
      touched: {name: nameTouched, address: addressTouched, phone: phoneTouched},
      handleChange
    } = this.props;
    return (
      <form>
        <label>Name</label>
        <input type="text" value={name} onChange={handleChange('name')}/>
        {nameError && nameTouched ? <div>{nameError}</div>}
        
        <label>Address</label>
        <input type="text" value={address} onChange={handleChange('address')}/>
        {addressError && addressTouched ? <div>{addressError}</div>}
        
        <label>Phone</label>
        <input type="text" value={phone} onChange={handleChange('phone')}/>
        {phoneError && phoneTouched ? <div>{phoneError}</div>}
      </form>
    );
  }
}

// ------- HERE'S THE IMPORTANT BIT -------
function mapStateToProps(state) {
  return { form: state.contacts };
}
export default 
  connect(mapStateToProps)
  (reduxForm('contacts', contactValidation)
  (ContactForm))

Notice that we're just using vanilla <input> elements there is no state in the ContactForm component. I have left handling onSubmit as an exercise for the reader. Hint: your data is in this.props.data.

ES7 Decorator Sugar

Using ES7 decorators, the example above could be written as:

@connect(state => ({ form: state.contacts }))
@reduxForm('contacts', contactValidation)
export default class ContactForm extends Component {

Much nicer, don't you think?

Validation

You may optionally supply a 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>, config:Object)

-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.

- config: Object [optional]

some control over when to mark fields as "touched" in the form:

config.touchOnBlur : boolean [optional]

marks fields to touched when the blur action is fired. defaults to true

config.touchOnChange : boolean [optional]

marks fields to touched when the change action is fired. defaults to false

@reduxForm(sliceName: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

- validation : Function [optional]

your validation function

props

The props passed into your decorated component will be:

-data:Object

The form data, in the form { field1: <string>, field2: <string> }

-dirty:boolean

true if the form data has changed from its initialized values. Opposite of pristine.

-errors:Object

All the errors, in the form { field1: <string>, field2: <string> }

-handleBlur(field:string) : Function

Returns a handleBlur function for the field passed.

-handleChange(field:string) : Function

Returns a handleChange function for the field passed.

-initializeForm(data:Object) : Function

Initializes the form data to the given values. All dirty and pristine state will be determined by comparing the current data with these initialized values.

-invalid:boolean

true if the form has validation errors. Opposite of valid.

-pristine:boolean

true if the form data is the same as its initialized values. Opposite of dirty.

-resetForm() : Function

Resets all the values in the form to the initialized state, making it pristine again.

-touch(...field:string) : Function

Marks the given fields as "touched" to show errors.

-touched:Object

the touched flags for each field, in the form { field1: <boolean>, field2: <boolean> }

-touchAll() : Function

Marks all fields as "touched" to show errors. should be called on form submission.

-untouch(...field:string) : Function

Clears the "touched" flag for the given fields

-untouchAll() : Function

Clears the "touched" flag for the all fields

-valid:boolean

true if the form passes validation (has no validation errors). Opposite of invalid.

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.

redux-form's People

Contributors

erikras avatar johanneslumpe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

rubythonode

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.