📜 ⬆️ ⬇️

Redux-form. When to work with forms is simple

I think most people know the redux library operation scheme: view → action → middlewares → reducers → state → view

Details here .

I want to bring to your attention a library that works on the same principle for forms.
')
image

Documentation in English. Install:

npm install redux-form 

We connect to our application:

 import { createStore, combineReducers } from 'redux' import { reducer as formReducer } from 'redux-form' const reducers = { //   form: formReducer //  state        form } const reducer = combineReducers(reducers) const store = createStore(reducer) 

Create a form:

 import React, { Component } from 'react'; //    (Field)     (reduxForm) import { Field, reduxForm } from 'redux-form'; class Form extends Component { render(){ //   handleSubmit    // reset    ,     //     undefined,      const {handleSubmit, reset} = this.props; const submit = (values) => console.log(values); return ( <form onSubmit={handleSubmit(submit)}> {/*   ,    ,   */} <Field name="title" component="input" type="text"/> <Field name="text" component="input" type="text"/> <div> <button type="button" onClick={reset}> </button> <button type="submit"> </button> </div> </form> ); } } Form = reduxForm({ form: 'post', //    state (state.form.post) })(Form); export default Form; 

Consider the situation when you need to drop the handler from the component level above:

Create a component:

 import React, { Component } from 'react'; import Form from './Form' class EditPost extends Component{ constructor(props) { super(props); } handleSubmit = (values) => { console.log(values); }; render() { let {post, dispatch} = this.props; return ( <div> {/*  */} <Form onSubmit={this.handleSubmit} /> </div> ); } } 

And change our form:

 //  <form onSubmit={handleSubmit(submit)}>  <form onSubmit={handleSubmit}> 

If we need to set a value, during initialization we use actionCreator initialize, which takes the name of the form as the first parameter, the second object with the values. For example, for an article on id:

 import React, { Component } from 'react'; //   import {initialize} from 'redux-form'; import {connect} from 'react-redux'; import Form from './Form' class EditPost extends Component{ constructor(props) { super(props); // post = {title: "   ", text: "   "} let {post, initializePost} = this.props; //  initializePost(post); } handleSubmit = (values) => { console.log(values); }; render() { return ( <div> <Form onSubmit={this.handleSubmit} /> </div> ); } } //   props     function mapDispatchToProps(dispatch){ return { initializePost: function (post){ dispatch(initialize('post', post)); } } } //   props     function mapStateToProps(state, ownProps){ const id = ownProps.params.id; return { post: state.posts[id] } } export default connect(mapStateToProps, mapDispatchToProps)(EditPost); 

The rest of the action creators can be viewed here .

If we are not satisfied with the standard field, we can transfer our version of the layout and actions:

 import React, { Component } from 'react'; import { Field, reduxForm } from 'redux-form'; class Form extends Component { // ,     renderField = ({ input, label, type}) => ( <div> <label>{label}</label> <div> <input {...input} placeholder={label} type={type}/> </div> </div> ); render(){ const {handleSubmit, reset} = this.props; return ( <form onSubmit={handleSubmit}> {/*     */} <Field name="title" component={this.renderField} label="" type="text"/> <Field name="text" component={this.renderField} label="" type="text"/> <div> <button type="button" onClick={reset}> </button> <button type="submit"> </button> </div> </form> ); } } Form = reduxForm({ form: 'post' })(Form); export default Form; 

Read more about the Field component.

Redux-form supports three types of validation:


For synchronous and asynchronous validation, create the formValidate.js file:

 //   export const validate = values => { const errors = {}; if(!values.text){ errors.text = '   !'; } else if (values.text.length < 15) { errors.text = '     15 !' } //         return errors }; const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) //  //     redux dispatch export const asyncValidate = (values/*, dispatch */) => { return sleep(1000) //    .then(() => { if (!values.title) { //         throw {title: '   !'} } else if (values.title.length > 10) { throw {title: '     10 !'} } }) }; 

For validation during a submission, the submission handler must be modified so that it returns a promise:

 import React, { Component } from 'react'; //      import {initialize, SubmissionError} from 'redux-form'; import {connect} from 'react-redux'; import Form from './Form'; const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); class EditPost extends Component{ constructor(props) { super(props); } handleSubmit = (values) => { /*   erros     ,    -      , {title: "  "}*/ return sleep(1000) {//   } .then(({errors, ...data}) => { if (errors) { //        // _error     throw new SubmissionError({ ...errors, _error: '  !' }) } else { //  ,   data } }) }; render() { return ( <div> {/*  */} <Form onSubmit={this.handleSubmit} /> </div> ); } } function mapDispatchToProps(dispatch){ return { initializePost: function (post){ dispatch(initialize('post', post)); } } } function mapStateToProps(state, ownProps){ const id = ownProps.params.id; return { post: state.posts[id] } } export default connect(mapStateToProps, mapDispatchToProps)(EditPost); 

And now let's turn on the validation and organize the error output:

 import React, { Component } from 'react'; import { Field, reduxForm } from 'redux-form'; import {validate, asyncValidate} from '../formValidate'; class Form extends Component { renderField = ({ input, label, type, meta: { touched, error, warning }}) => ( <div> <label>{label}</label> <div> <input {...input} placeholder={label} type={type}/> {/*   */} {touched && ((error && <div>{error}</div>))} </div> </div> ); render(){ const {handleSubmit, reset, error} = this.props; return ( <form onSubmit={handleSubmit}> {/*     */} <Field name="title" component={this.renderField} label="" type="text"/> <Field name="text" component={this.renderField} label="" type="text"/> <div> <button type="button" onClick={reset}> </button> <button type="submit"> </button> {/*   */} {error && <div>{error}</div>} </div> </form> ); } } Form = reduxForm({ form: 'post', //   validate, asyncValidate })(Form); export default Form; 

For those who want to see an example of work, do this:

  git clone https://github.com/BoryaMogila/koa_react_redux.git; git checkout redux-form; npm install; npm run-script run-with-build; 

And try a CRUD application using the redux-form at the link localhost (127.0.0.1): 4000 / app /.

With asynchronous validation, confusion is possible: when you press submission before responding from the server, the submission will work.

There is much more interesting and useful in the documentation . I recommend for viewing.

PS: As always, I'm waiting for a constructive.

Source: https://habr.com/ru/post/313966/


All Articles