@promotively/react-redux-form
v4.1.0-beta.1
Published
Universal/isomorphic react.js/redux.js javascript/typescript library for building forms.
Downloads
148
Maintainers
Readme
@promotively/react-redux-form
Universal/isomorphic react.js/redux.js javascript/typescript library for building forms.
Why?
- You are using redux.js in your app.
- You are frustrated with using redux-form and the lack of alternative solutions.
- You need a form library that has dual API's for working with higher order components or hooks with react.js.
- You want an easy yet powerful and performant way to build forms that closely matches building normal html forms.
- You are building a new app and want to use redux.js to handle your form state.
- You plan on building complicated form flows that can be difficult to accomplish without redux.js.
- You have existing repetitive form related react.js/redux.js boilerplate that you want to refactor.
- You want a proper form state abstraction layer but don't have the time to build one.
- You want to be able to debug your forms through redux dev tools.
- You need a library that is compatible with server side rendering (server side state management).
- You want to use a library that has been extensively battle tested and built to handle all typical (and not so typical) form behaviours in modern web applications.
- You need to handle advanced A/B testing scenarios with your forms.
- You want to retain your form state even when a form is not rendered (ie: multi step forms)
- You need to integrate with external applications and/or tools and need an API that is not react.js based.
- You need to know if a form or input has been touched, changed or completed.
- You need client side async/sync validation on a form or input(s).
Installation
With Yarn
yarn add @promotively/react-redux-form
With NPM
npm install @promotively/react-redux-form
Example
Advanced examples using higher order components and hooks rendered with nodejs and web browsers are available inside the /example
folder.
Once you have executed yarn build
go to the dist/example
folder and from there you can open the index.html
file to run the example.
The example is also available online.
Documentation
The source code is documented using JSDoc syntax and documentation is generated using jsdoc.
Once you have executed yarn docs
documentation is available inside the dist/docs
folder.
Documentation for the most recent release is also available online.
TypeScript definitions are also available in the dist/lib
folder.
Setup
Add reducer
to your redux store and make sure that redux-thunk
is also added to your store middleware.
// store.js
import { applyMiddleware, combineReducers, createStore } from 'redux';
import { reducer } from '@promotively/react-redux-form';
import thunk from 'redux-thunk';
export const store = createStore({ form: reducer }, applyMiddleware(...[thunk]));
Usage
Use the provided form and input components to compose a form. (id is the only prop that is required)
// components/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
export const LoginForm = props => (
<Form id={props.id}>
<Input id="email" name="Email" type="email" />
<Input id="password" name="Password" type="password" />
<button>Submit</button>
</Form>
);
// app.js
import { render } from 'react-dom';
import { createReduxStore } from './store';
import { LoginForm } from 'components/login-form';
const store = createReduxStore();
const app = (
<Provider store={store}>
<LoginForm id="login-form-example" />
</Provider>
);
render(app, document.getElementsByTagName('main')[0]);
(Optional) Use custom form and input components.
// components/custom-form.js
import React from 'react';
export const CustomForm = props => (
<div>
{props.error ? error : null}
<form {...props} />
</div>
);
// components/custom-input.js
import React from 'react';
export const CustomInput = props => (
<label>
<span>{props.name}</span>
<input {...props} />
{props.touched && props.error ? error : null}
</label>
);
// components/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
import { CustomForm } from 'components/custom-form';
import { CustomInput } from 'components/custom-input';
export const LoginForm = props => (
<Form id={props.id} component={CustomForm}>
<Input id="email" name="Email" type="email" component={CustomInput} />
<Input id="password" name="Password" type="password" render={props => <CustomInput {...props} />} />
<button>Submit</button>
</Form>
);
(Optional) Add a submission handler to the form.
// components/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
const handleFormSubmit = data => axios.post('http://localhost:3000/api/v1/login', data).then(response => response.data);
export const LoginForm = props => (
<Form id={props.id} onSubmit={handleFormSubmit}>
<Input id="email" name="Email" type="email" />
<Input id="password" name="Password" type="password" />
<button>Submit</button>
</Form>
);
(Optional) Add validation (synchronous or asynchronous) to the form.
// component/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
const handleFormValidation = data => {
if (data.email) {
return new Promise((resolve, reject) => {
if (!data.email.includes('@')) {
reject(new Error('email is invalid'));
} else {
resolve();
}
});
}
if (!data.email) {
return 'email is required';
}
if (!data.password) {
return 'password is required';
}
};
const handleFormSubmit = data => axios.post('http://localhost:3000/api/v1/login', data).then(response => response.data);
export const LoginForm = props => (
<Form id={props.id} validate={handleFormValidation} onSubmit={handleFormSubmit}>
<Input id="email" name="Email" type="email" />
<Input id="password" name="Password" type="password" />
<button>Submit</button>
</Form>
);
(Optional) Disable the form when there are no changes detected or validation errors are found.
// components/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
const handleFormSubmit = data => axios.post('http://localhost:3000/api/v1/login', data).then(response => response.data);
export const LoginForm = props => (
<Form id={props.id} onSubmit={handleFormSubmit}>
<Input id="email" name="Email" type="email" />
<Input id="password" name="Password" type="password" />
<button disabled={props.disabled}>Submit</button>
</Form>
);
(Optional) Avoid destroying the form state when the component unmounts.
// components/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
const handleFormSubmit = data => axios.post('http://localhost:3000/api/v1/login', data).then(response => response.data);
export const LoginForm = props => (
<Form id={props.id} onSubmit={handleFormSubmit} destroy={false}>
<Input id="email" name="Email" type="email" />
<Input id="password" name="Password" type="password" />
<button>Submit</button>
</Form>
);
(Optional) Add validation (synchronous or asynchronous) to the inputs.
// component/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
const handleInputEmailValidation = (id, value) => (
new Promise((resolve, reject) => {
if (!value) {
reject(new Error('email is required'));
else if (!value.includes('@')) {
reject(new Error('email is invalid'));
} else {
resolve();
}
})
);
const handleInputPasswordValidation = (id, value) => (
if (!value) {
return 'password is required';
}
);
export const LoginForm = props => (
<Form id={props.id}>
<Input id="email" name="Email" type="email" validate={handleInputEmailValidation} />
<Input id="password" name="Password" type="password" validate={handleInputPasswordValidation} />
<button>Submit</button>
</Form>
);
(Optional) Add a default value to a input.
// component/login-form.js
import React from 'react';
import { Form, Input } from '@promotively/react-redux-form';
export const LoginForm = props => (
<Form id={props.id}>
<Input id="email" name="Email" type="email" value="[email protected]" />
<Input id="password" name="Password" type="password" />
<button>Submit</button>
</Form>
);
API
Redux Action Creators
| Function | Arguments | Description |
| --------------- | ----------------------------------------- | --------------------------------- |
| completeForm
| (formId) | Completes a form. |
| createForm
| (formId) | Create a form. |
| errorForm
| (formId, error) | Set the error state on a form. |
| loadingForm
| (formId) | Sets the loading state on a form. |
| submitForm
| (formId, data, action) | Submit a form. |
| destroyForm
| (formId) | Destroy a form. |
| resetForm
| (formId) | Reset all input values in a form. |
| blurInput
| (formId, inputId) | Blur a input. |
| changeInput
| (formId, inputId, defaultValue, newValue) | Change the value of a input. |
| completeInput
| (formId, inputId) | Complete the value of a input. |
| createInput
| (formId, inputId, defaultValue) | Create a input. |
| disableInput
| (formId, inputId) | Disable a input. |
| enableInput
| (formId, inputId) | Enable a input. |
| errorInput
| (formId, inputId, error) | Set the error on a input. |
| focusInput
| (formId, inputId) | Focus a input. |
| destroyInput
| (formId, inputId) | Destroy a input. |
| resetInput
| (formId, inputId) | Reset an input value. |
React Components
| Function | Arguments | Description | Props |
| ------------------- | --------- | --------------------------------------------------------------- | ----------------------------------------------------------------------- |
| FormComponent
| (props) | React.js component to render forms. | { ...HTMLFormElementProps, ...HTMLElementProps, component, render } |
| InputComponent
| (props) | React.js component to render inputs. | { ...HTMLInputElementProps, ...HTMLElementProps, component, render } |
| SelectComponent
| (props) | React.js component to render selects. | { ...HTMLSelectElementProps, ...HTMLElementProps, component, render } |
| TextareaComponent
| (props) | React.js component to render textareas. | { ...HTMLTextareaElementProps, ...HTMLElementProps, component, render } |
| Form
| (props) | React.js container component to render forms with redux.js. | { ...HTMLFormElementProps, ...HTMLElementProps, component, render } |
| Input
| (props) | React.js container component to render inputs with redux.js. | { ...HTMLInputElementProps, ...HTMLElementProps, component, render } |
| Select
| (props) | React.js container component to render selects with redux.js. | { ...HTMLInputElementProps, ...HTMLElementProps, component, render } |
| Textarea
| (props) | React.js container component to render textareas with redux.js. | { ...HTMLInputElementProps, ...HTMLElementProps, component, render } |
React Higher Order Components
| Function | Arguments | Description | Props |
| ----------- | --------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| withForm
| (options) | An object containing configuration options. | { ...HTMLFormElementProps, ...HTMLElementProps, touched, complete, data, touched, error, errorForm, loading, validate } |
| withInput
| (options) | An object containing configuration options. | { ...HTMLInputElementProps, ...HTMLElementProps, touched, complete, touched, error, focus, validate } |
React Hooks
| Function | Arguments | Description | Props |
| ----------- | --------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| useForm
| (id, options) | An object containing configuration options. | { ...HTMLFormElementProps, ...HTMLElementProps, touched, complete, data, touched, error, errorForm, loading, validate } |
| useInput
| (id, options) | An object containing configuration options. | { ...HTMLInputElementProps, ...HTMLElementProps, touched, complete, touched, error, focus, validate } |
Redux Reducers
| Function | Description |
| -------------- | ------------------------------------------------------------------------------- |
| reducer
| A combined redux.js reducer to handle all state mutations for forms and inputs. |
| formReducer
| A redux.js reducer function to handle the state mutations for forms. |
| inputReducer
| A redux.js reducer function to handle the state mutations for inputs. |
React Redux Selectors
| Function | Description |
| ------------------------------- | --------------------------------------------------------------------------- |
| createFormCompleteSelector
| Create a reselect.js selector function to get the form complete state. |
| createFormDirtySelector
| Create a reselect.js selector function to get the form touched state. |
| createFormDisabledSelector
| Create a reselect.js selector function to get the form disabled state. |
| createFormErrorSelector
| Create a reselect.js selector function to get the form error state. |
| createFormLoadingSelector
| Create a reselect.js selector function to get the form loading state. |
| createFormPayloadSelector
| Create a reselect.js selector function to get the form payload. |
| createFormReadySelector
| Create a reselect.js selector function to get the form ready state. |
| createFormTouchedSelector
| Create a reselect.js selector function to get the form touched state. |
| createFormValuesSelector
| Create a reselect.js selector function to get the last form payload. |
| createInputCompleteSelector
| Create a reselect.js selector function to get the input complete state. |
| createInputDirtySelector
| Create a reselect.js selector function to get the input touched state. |
| createInputDisabledSelector
| Create a reselect.js selector function to get the input disabled state. |
| createInputErrorSelector
| Create a reselect.js selector function to get the input error state. |
| createInputFocusSelector
| Create a reselect.js selector function to get the input focus state. |
| createInputReadySelector
| Create a reselect.js selector function to get the input ready state. |
| createInputRevalidateSelector
| Create a reselect.js selector function to get the input revalidation state. |
| createInputTouchedSelector
| Create a reselect.js selector function to get the input touched state. |
| createInputValueSelector
| Create a reselect.js selector function to get the input value state. |
Build
All build artifacts can be found inside the dist/lib
and dist/example
folders after running yarn build
.
Linting
This library uses @promotively/eslint-config and @promotively/eslint-config-react for its ESLint configuration.
yarn lint
Tests
This library has 100% unit test code coverage.
Code coverage is available inside the dist/coverage
folder after running yarn test
.
Code coverage for the most recent release is also available online.
Contact
Feel free to reach out using any of the below methods:
License
MIT