Form表单思维导图

demo
import React, { Component, useEffect } from "react";
import Form, { Field } from "../components/my-rc-field-form/";
import Input from "../components/Input";
const nameRules = { required: true, message: "请输入姓名!" };
const passworRules = { required: true, message: "请输入密码!" };
export default class MyRCFieldForm 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>MyRCFieldForm</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>
<button>Submit</button>
</Form>
</div>
);
}
}
入口
import React from "react";
import _Form from "./Form";
import Field from "./Field";
import useForm from "./useForm";
const Form = React.forwardRef(_Form);
Form.Field = Field;
Form.useForm = useForm;
export { Field, useForm };
export default Form;
Form组件
import React from "react";
import FieldContext from "./FieldContext";
import useForm from "./useForm";
export default function Form(
{ children, form, onFinish, onFinishFailed },
ref
) {
const [formInstance] = useForm(form);
React.useImperativeHandle(ref, () => formInstance);
formInstance.setCallbacks({
onFinish,
onFinishFailed,
});
return (
<form
onSubmit={(e) => {
e.preventDefault();
formInstance.submit();
}}
>
<FieldContext.Provider value={formInstance}>
{children}
</FieldContext.Provider>
</form>
);
}
- ref传给子组件的时候不在props里,会独立出来
- useImperativeHandle:将formInstance反弹给父组件使用(getFieldValue、setFieldsValue等方法)
Field组件
import React, { Component } from "react";
import FieldContext from "./FieldContext";
export default class Field extends Component {
static contextType = FieldContext;
componentDidMount() {
this.unregister = this.context.registerFieldEntities(this);
}
componentWillUnmount() {
this.unregister();
}
onStoreChange = () => {
this.forceUpdate();
};
getControlled = () => {
const { getFieldValue, setFieldsValue } = this.context;
const { name } = this.props;
return {
value: getFieldValue(name),
onChange: (e) => {
const newValue = e.target.value;
setFieldsValue({ [name]: newValue });
},
};
};
render() {
const { children } = this.props;
const returnChildNode = React.cloneElement(children, this.getControlled());
return returnChildNode;
}
}
- 这里不能用useEffect,useEffect会延时执行注册,componentDidMount里的更新会被忽略掉,只能用useLayoutEffect注册
FormStore和useForm
// 定义状态管理库
import { useRef } from "react"
class FormStore {
constructor() {
this.store = {}
this.fieldEntities = []
this.callbacks = {}
}
setCallbacks = (callbacks) => {
this.callbacks = { ...this.callbacks, ...callbacks }
}
// 注册实例(forceUpdate)
// 注册与取消注册
// 订阅与取消订阅
registerFieldEntities = (entity) => {
this.fieldEntities.push(entity)
return () => {
this.fieldEntities = this.fieldEntities.filter((item) => item !== entity)
delete this.store[entity.props.name]
}
}
// get
getFieldsValue = () => {
return { ...this.store }
}
getFieldValue = (name) => {
return this.store[name]
}
// set
// password: 123
setFieldsValue = (newStore) => {
// 1. update store
this.store = {
...this.store,
...newStore,
}
// 2. update Field 数据更新之后组件也得更新
this.fieldEntities.forEach((entity) => {
Object.keys(newStore).forEach((k) => {
if (k === entity.props.name) {
entity.onStoreChange()
}
})
})
}
validate = () => {
let err = []
// todo 校验
// 简版校验
this.fieldEntities.forEach((entity) => {
const { name, rules } = entity.props
const value = this.getFieldValue(name)
let rule = rules[0]
if (rule && rule.required && (value === undefined || value === "")) {
err.push({ [name]: rule.message, value })
}
})
return err
}
submit = () => {
console.log("submit")
let err = this.validate()
// 提交
const { onFinish, onFinishFailed } = this.callbacks
if (err.length === 0) {
// 校验通过
onFinish(this.getFieldsValue())
} else {
// 校验不通过
onFinishFailed(err, this.getFieldsValue())
}
}
getForm = () => {
return {
getFieldsValue: this.getFieldsValue,
getFieldValue: this.getFieldValue,
setFieldsValue: this.setFieldsValue,
registerFieldEntities: this.registerFieldEntities,
submit: this.submit,
setCallbacks: this.setCallbacks,
}
}
}
export default function useForm(form) {
// 存值,在组件卸载之前指向的都是同一个值
const formRef = useRef()
if (!formRef.current) {
if (form) {
formRef.current = form
} else {
const formStore = new FormStore()
formRef.current = formStore.getForm()
}
}
return [formRef.current]
}
- 关注store、fieldEntities和callBacks的变更以及获取
- 每次setFieldsValue之后应该从注册里获取Field组件强制更新的方法并执行
- 区别函数式组件和类组件使用context的区别
FieldContext
import React from "react";
const FieldContext = React.createContext();
export default FieldContext;