Create Redux Form
What is This?
Redux Form is a great library for creating and managing forms and their state in redux applications. But, it leaves a lot of common boilerplate code up for the user to implement. This library aims to remove this duplication of code while at the same time keeping the ability to define your own custom form components.
Install
To install, run yarn add create-redux-form
or npm install create-redux-form
.
Create Your Form Generator
First, you'll need redux-form
compatible input components. See Redux Form Field Usage.
Once you have the components you need you can go ahead and create your custom generator like this:
/* form-generator.js */ const form wizardForm =
The object passed in as the first parameter will be the UIKit
used to generate your forms.
Generate a Form or Wizard Form
This is how you would then use your generator to generate a form. Both form
and wizardForm
take two parameters, a formName
and a schema
.
/* validation.js */const required = v ? undefined : ` is required.`const number = Number ? ` must be a number.` : undefined
/* buy-pnk-form.js */ const Form: BuyPNKForm // The form react component isInvalid: getBuyPNKFormIsInvalid // A redux state selector that returns true if the form's validation passed and false otherwise submit: submitBuyPNKForm // An action creator that returns an action object that submits the form when dispatched} =
If you wanted a wizard form instead, all you need to do is nest the schema one level deeper with components grouped in "steps". E.g.
/* buy-pnk-wizard-form.js */ const Form: BuyPNKForm isInvalid: getBuyPNKFormIsInvalid submit: submitBuyPNKForm } =
Breaking Down The Form Schema
These are all the properties you can have in a schema.
const schema: // The key gets passed to your component as the prop `placeholder` after being converted from `camelCase` to `TitleCase`. E.g. accountUsername => Account Username placeholder: type: string // This is the component you want to use from the `UIKit` passed in to `createReduxForm` // Validator functions or functions that take the field's placeholder and return a validator function, like the examples above, (`required`, `number`). Validator functions should return undefined if the checks passed or a string with an error message for the failure validate: | undefined | string | undefined | string visibleIf: string // Only render this field if the value of the specified field is truthy or falsy. I.e. `visibleIf: 'email'` or `visibleIf: '!email'` // `redux-form` [formValues](https://redux-form.com/7.2.3/docs/api/formvalues.md/) formValues: boolean props: object // Props to pass down to your component reduxFormFieldProps: object // Props to pass to `redux-form`'s [Field](https://redux-form.com/7.2.3/docs/api/field.md/) component } = email: type: 'text' validate: v ? undefined : ` is required.` visibleIf: 'username' formValues: currentUsername: 'username' props: placeholder: 'Secondary Email' // You can override the default placeholder, `camelToTitleCase(key)`, like this too reduxFormFieldProps: v
Rendering the Form and WizardForm
This is how you would render and use the Form.
const Component = <div> /* In addition to these props, you can also pass in any prop that a `redux-form` [form](https://redux-form.com/7.2.3/docs/api/reduxform.md/) takes */ <BuyPNKForm onSubmit= `We submitted! ` // Do what you need to do with the data className="BuyPNKForm" // Inner `fieldset` will have class name `BuyPNKForm-fieldset` and inner `fields` will have class name `BuyPNKForm-fieldset-fields` disabled=false /> <button onClick=submitBuyPNKForm disabled=buyPNKFormIsInvalid> Submit </button> </div> buyPNKFormIsInvalid: submitBuyPNKForm Component
This is how you would render and use the WizardForm.
state = currentPage: 0 hasPrevPage: false hasNextPage: false totalPages: 0 thisbackHandlerRef = ref { console this } { const buyPNKFormIsInvalid submitBuyPNKForm = thisprops const hasPrevPage hasNextPage = thisstate return <div> /* In addition to these props, you can also pass in any prop that a `create-redux-form` Form takes and they will be applied to the current page in the wizard */ <BuyPNKForm onSubmit= `We submitted! ` // Do what you need to do with the data backHandlerRef=thisgetBackHandlerRef onPageChange=thishandlePageChange transitionName="someCSSAnimation" // Default is `carousel` and can be imported from the module, i.e. `@import '~create-redux-form/animations/carousel.css';` className="BuyPNKWizardForm" // Inner `Form` will have class name `BuyPNKWizardForm-form` /> hasPrevPage && <button onClick=thisbackHandlerRef>Go Back</button> <button onClick=submitBuyPNKForm disabled=buyPNKFormIsInvalid> hasNextPage ? 'Next' : 'Submit' </button> </div> } buyPNKFormIsInvalid: submitBuyPNKForm Component
Rendering Decorational/Informational Components
Because you create your own UIKit
to pass into the createReduxForm
, it is very easy to extend your schema to support purely decorational components. Here is how you would make a simple info box.
const FormInfo = <div className="FormInfo"> <h5 className="FormInfo-text">value</h5> </div> FormInfopropTypes = input: PropTypesshape value: PropTypesstringisRequired isRequired
Then, when rendering the form that contains this field, you pass in the value in the redux-form
initialValues
prop.
<SomeForm enableReinitialize // Enable this if the value is dynamic, so the form rerenders when it changes keepDirtyOnReinitialize // This lets you keep the value of the other fields when the form reinitializes initialValues= yourFieldSchemaKey: `Here is your info: ` />