- Redux Form
- Getting Started
Getting Started With redux-form
#
The basic implementation of redux-form
is simple. However, to make the most of it, it's recommended to have basic knowledge on:
- Redux state container,
- React and Higher-Order Components (HOCs).
Overview #
To connect your React form components to your Redux store you'll need following pieces from the redux-form
package:
- Redux Reducer:
formReducer
, - React HOC
reduxForm()
and<Field/>
component.
It's important to understand their responsibilities:
type | responsibility | |
---|---|---|
formReducer |
reducer | function that tells how to update the Redux store based on changes coming from the application; those changes are described by Redux actions |
reduxForm() |
HOC | function that takes configuration object and returns a new function; use it to wrap your form component and bind user interaction to dispatch of Redux actions |
<Field/> |
component | component that lives inside your wrapped form component; use it to connect the input components to the redux-form logic |
Data flow #
The diagram below represents the simplified data flow. Note that in most cases you don't need to worry about the action creators for yourself, as they're already bound to dispatch for certain actions.
Let's go through a simple example. We have a form component wrapped with reduxForm()
. There is one text input inside, wrapped with <Field/>
. The data flows like this:
- User clicks on the input,
- "Focus action" is dispatched,
formReducer
updates the corresponding state slice,- The state is then passed back to the input.
Same goes for any other interaction like filling the input, changing its state or submitting the form.
With redux-form
comes a lot more: hooks for validation and formatting handlers, various properties and action creators. This guide describes the basic usage – feel free to dig deeper.
Basic Usage Guide #
Step 1 of 4: Form reducer #
The store should know how to handle actions coming from the form components. To enable this, we need to pass the formReducer
to your store. It serves for all of your form components, so you only have to pass it once.
import { createStore, combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'
const rootReducer = combineReducers({
// ...your other reducers here
// you have to pass formReducer under 'form' key,
// for custom keys look up the docs for 'getFormState'
form: formReducer
})
const store = createStore(rootReducer)
Now your store knows how to handle actions coming from the form components.
NOTE: The key used to pass the redux-form
reducer should be named form
. If you need a custom key for some reason see getFormState
config for more details.
Step 2 of 4: Form component #
To make your form component communicate with the store, we need to wrap it with reduxForm()
. It will provide the props about the form state and function to handle the submit process.
import React from 'react'
import { Field, reduxForm } from 'redux-form'
let ContactForm = props => {
const { handleSubmit } = props
return (
<form onSubmit={ handleSubmit }>
{ /* form body*/ }
</form>
)
}
ContactForm = reduxForm({
// a unique name for the form
form: 'contact'
})(ContactForm)
export default ContactForm;
Once we have the form component ready, it's time to add some inputs.
NOTE: If the ()()
syntax seems confusing, you can always break it down into two steps:
// ...
// create new, "configured" function
createReduxForm = reduxForm({ form: 'contact' })
// evaluate it for ContactForm component
ContactForm = createReduxForm( ContactForm )
export default ContactForm;
Step 3 of 4: Form <Field/>
Components #
The <Field/>
component connects each input to the store. The basic usage goes as follows:
<Field name="inputName" component="input" type="text" />
It creates an HTML <input/>
element of type text
. It also passes additional props such as value
, onChange
, onBlur
, etc. Those are used to track and maintain the input state under the hood.
NOTE: <Field/>
component is much more powerful. Apart from basic input types, it can take a class or a stateless component. When you're ready, go to the docs to find out more.
Let's finish up our contact form:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
let ContactForm = props => {
const { handleSubmit } = props
return (
<form onSubmit={ handleSubmit }>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" />
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text" />
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Submit</button>
</form>
)
}
ContactForm = reduxForm({
// a unique name for the form
form: 'contact'
})(ContactForm)
export default ContactForm;
From now on, the store should be populated based on actions coming from your form component. We can now handle the submission.
Step 4 of 4: Reacting to submit #
The submitted data is passed as JSON object to your onSubmit
function. Let's console.log
it out:
import React from 'react'
import ContactForm from './ContactForm'
class ContactPage extends React.Component {
submit = (values) => {
// print the form values to the console
console.log(values)
}
render() {
return (
<ContactForm onSubmit={this.submit} />
)
}
}
You can now take it from here. We recommend to check out the examples. The common next steps could also be:
- setting the initial form values,
- implementing the validation,
- creating dynamic forms with arrays of fields.