Let’s take a look at the implementation of the form first!
- After reading the source code of ANTD, IT is found that ANTD3 and ANTD4 are very different in the implementation of forms.
- Antd3 is designed to realize the collection, verification, submission and other features of form data. Extend by using higher-order components. The higher-order component passes an input component wrapper function to the form component to take over the input events of the input component and manage the form data uniformly. The implementation of verification function is that the higher-order component passes a verification function to the form so that it has the function of data verification.
- Antd4 is implemented based on rC-field-form. It is quite different from ANTD3 in data management
! Antd3 stores the data it needs to manage in the form's state, which can be costly to render. When the state of a child component changes, all the components in the form are re-rendered. Antd4 stores the data in a store for unified management, and the update of a set of price states will not cause the re-rendering of all components
- The preparation of form form based on RC-field-form
- Run the yarn add RC-filed-form command.
- Understand the basic use of RC-field-form
- Implement my-field-form yourself
- The directory structure
- input.js
- Index.js — entry file
- Form.js
- Field.js
- useForm.js
- Context.js – Passes data across hierarchies through context
- Rc-field-form is basically used
- Basic usage of class components
import React from 'react'; // import Form, { Field } from 'rc-field-form'; import Form, { Field } from '.. /.. /components/my-field-form'; import Input from '.. /.. /.. /components/input'; import './index.less'; Const nameRules = {required: true, message: "Please enter your name!" }; Const passworRules = {required: true, message: "Please enter password!" }; class RcFormUse extends Component{ formRef = React.createRef(); componentDidMount() { console.log("form", this.formRef.current); // this.formRef.current.setFieldsValue({username: "default"}); } onFinish = val => { console.log("onFinish", val); }; OnFinishFailed = val => {console.log("onFinishFailed", val); }; render () { return ( <div> <h3>RcFormUse</h3> <Form ref={this.formRef} onFinish={this.onFinish} onFinishFailed={this.onFinishFailed} > <Field name="username" rules={nameRules}> <Input placeholder="Username" /> </Field> <Field name="password" rules={passworRules}> <Input placeholder=" password" /> </Field> </Form> </div> ) } } export default RcFormUse;Copy the code
- Functional components are basically used
import React from 'react'; // import Form, { Field } from 'rc-field-form'; import Form, { Field } from '.. /.. /components/my-field-form'; import Input from '.. /.. /.. /components/input'; import './index.less'; Const nameRules = {required: true, message: "Please enter your name!" }; Const passworRules = {required: true, message: "Please enter password!" }; Const RcFormUse = (props) => {// useForm is a custom component const [form] = form.useForm (); const onFinish = val => { console.log("onFinish", val); }; // Form verification failed const onFinishFailed = val => {console.log("onFinishFailed", val); }; UseEffect () => {// Set the default form.setfieldsValue ({username: "default"}); } []); return ( <div> <h3>RcFormUse</h3> <Form ref={this.formRef} onFinish={this.onFinish} onFinishFailed={this.onFinishFailed} > <Field name="username" rules={nameRules}> <Input placeholder=" username" Rules ={passworRules}> <Input placeholder=" please Input password "/> </Field> <button> commit </button> </Form> </div>)} export default RcFormUse;Copy the code
- Input component encapsulation
import React from 'react'; const Input = (props) => { return <input {... props}></input> } const CustomInput = (props) => { const {value, otherProps} = props; return <Input style={{outline: 'none'} value={value} {... otherProps}></Input> } export default CustomInput;Copy the code
- Index.js entry file
import React from 'react'; import _Form from './Form'; import Field from './Filed'; import useForm from './useForm'; Const Form = react.forwardref (_Form); Form.useForm = useForm; export {Field}; export default Form;Copy the code
- Context.js
import React from 'react'; Const FieldContex = React. CreacteContext; export default FieldContext;Copy the code
- useForm.js
import React from 'react'; Class FormStore {constructor() {this.store = {}} Use to force updates to this.fieldEntities = {}; SetCallbacks = (callback) => {this.callbacks = {this.callbacks = {this.callbacks = {... this.callbacks, ... Callback,}} // Register component for component update registerEntity = entity => {/** entity => {props: {... }, getCntrolled: {... }, context: {... }, refs: {... }, state: null, unregisterEntity: {... }, updater: {... }, _reactInternalInstance: {... }, _reactInternals: {... }} **/ console.log(' Filed Component :', entity); this.fieldEntities = { ... this.fieldEntities, [entity.props.name]: Entity} // Unregister component return () => {delete this.fieldentities [entity.props. Name]; } } getFieldVal = (name) => { const v = this.store[name]; return v; } setFieldVal = (newStore) => { this.store ={ ... this.store, ... Keys (newStore).foreach (name => {this.fieldentities [name].onstorechange (); })} // Validate = () => {let err = []; // traverses this.entities object.keys (this.fieldentities). ForEach (const entity = this.fieldentities [key]; const { rules } = entity.props; Const value = this.getfieldVal (key); Const rule = rules && rules[0]; const rule = rules && rules[0]; // console.log('key:', key); // console.log('entity: ', entity); // console.log('rule: ', rule); // console.log('value:',value); if(rule && rule.required && value === undefined){ err.push({ [key]: rule.message, value, }); } }) return err; } // Submit = () => {const {onFinish, onFinishFailed} = this.callbacks; const err = this.validate(); if(err.length === 0) { onFinish && onFinish({... this.store}) } else { console.log('failed:', err); onFinishFailed && onFinishFailed(err, {... this.store}) } } getForm() { return { getFieldVal: this.getFieldVal, setFieldVal: this.setFieldVal, registerEntity: this.registerEntity, submit: this.submit, setCallbacks: This.setcallbacks,}}} // custom hook const useForm = () => {const formRef = react.useref (); if(! formRef.current) { const formStore = new FormStore(); formRef.current = formStore.getForm(); } return [formRef.current]; } export default useForm;Copy the code
- Form.js
import React, { useImperativeHandle } from 'react'; import useForm from './useForm'; import FieldContext from './FiledContext'; const Form = ({ children, onFinish, onFinishFailed }, ref) => { const [formInstance] = useForm(); The console. The log (' formInstance: 'formInstance); UseImperativeHandle (ref, forwardRef); useImperativeHandle(ref, forwardRef); () => formInstance); // Receive the method passed by the Form component, Stored in the useForm. Js in the callbacks formInstance. SetCallbacks ({onFinish, onFinishFailed }) const onSubmit = (e) => { e.preventDefault(); e.stopProstopPropagation(); formInstance.submit(); } return ( <form onClick={onSubmit}> <FieldContext.Provider value={formInstance}> {children} </FieldContext.Provider> </form> ) } export default Form;Copy the code
- Field.js
import React from 'react'; import FieldContext from './FiledContext'; class Field extends React.Component{ static contextType = FieldContext; ComponentDidMount () {/ / register the current object is added in the context enclosing unregisterEntity = enclosing context. RegisterEntity (this); } componentWillUnmount () {// Unsubscribe if(this.unregisterEntity) {this.unregisterEntity(); }} // Perform forced update onStoreChange() {this.forceUpdate(); } getCntrolled = () => { const { getFieldVal, setFieldVal } = this.context; const { name } = this.props; return { value: getFieldVal(name), onChange: (e) => { const newVal = e.target.value setFieldVal({[ name ]: newVal}); The console. The log (' value: 'newVal); } } } render(){ const { children } = this.props; return React.cloneElement(children, this.getCntrolled()) } } export default Field;Copy the code