高階組件版表單組件設(shè)計(jì)思路進(jìn)階
表單組件要求實(shí)現(xiàn)數(shù)據(jù)收集辛辨、校驗(yàn)、提交等特性旁蔼,可通過(guò)高階組件擴(kuò)展
高階組件給表單組件傳遞一個(gè)input組件包裝函數(shù)接管其輸入事件并統(tǒng)一管理表單數(shù)據(jù)
高階組件給表單組件傳遞一個(gè)校驗(yàn)函數(shù)使其具備數(shù)據(jù)校驗(yàn)功能
Input.js文件內(nèi)容如下:
import React, { Component } from 'react'
const Input = (props) => {
? ? return <input {...props} />
}
export default class CustomizeInput extends Component {
? ? constructor(props) {
? ? ? ? super(props);
? ? }
? ? render() {
? ? ? ? const { value = "", ...otherProps } = this.props;
? ? ? ? return (
? ? ? ? ? ? <div style={{padding: '10px'}}>
? ? ? ? ? ? ? ? <Input style={{outline: 'none'}} value={value} {...otherProps} />
? ? ? ? ? ? </div>
? ? ? ? )
? ? }
}
1.實(shí)現(xiàn)一個(gè)簡(jiǎn)單的表單功能:
MyRCForm.js文件內(nèi)容如下:
import React, { Component } from 'react'
import Input from '../components/Input';
class MyRCForm extends Component {
? ? constructor(props) {
? ? ? ? super(props);
? ? ? ? this.state = {
? ? ? ? ? ? username: "",
? ? ? ? ? ? password: ""
? ? ? ? }
? ? }
? ? nameChange = (e) => {
? ? ? ? this.setState({
? ? ? ? ? ? username: e.target.value
? ? ? ? })
? ? }
? ? passwordChange = (e) => {
? ? ? ? this.setState({
? ? ? ? ? ? password: e.target.value
? ? ? ? })
? ? }
? ? submit = () => {
? ? ? ? const { username, password } = this.state;
? ? ? ? console.log("syta", username, password); // sy-log
? ? }
? ? render() {
? ? ? ? const { username, password } = this.state;
? ? ? ? return (
? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? <h3>MyRCForm</h3>
? ? ? ? ? ? ? ? <Input
? ? ? ? ? ? ? ? ? ? placeholder="Username"
? ? ? ? ? ? ? ? ? ? value={username}
? ? ? ? ? ? ? ? ? ? onChange={this.nameChange}
? ? ? ? ? ? ? ? />
? ? ? ? ? ? ? ? <Input
? ? ? ? ? ? ? ? ? ? placeholder="Password"
? ? ? ? ? ? ? ? ? ? value={password}
? ? ? ? ? ? ? ? ? ? onChange={this.passwordChange}
? ? ? ? ? ? ? ? />
? ? ? ? ? ? ? ? <button onClick={this.submit}>submit</button>
? ? ? ? ? ? </div>
? ? ? ? )
? ? }
}
export default MyRCForm
2.使用rc-form的高階組件createForm:
MyRCForm.js文件內(nèi)容如下:
import React, { Component } from 'react'
import Input from '../components/Input';
import { createForm } from 'rc-form'; // 安裝rc-form:npm install rc-form
const nameRules = {required: true, message: "請(qǐng)輸入姓名袜瞬!"};
const passwordRules = {required: true, message: "請(qǐng)輸入密碼!"};
@createForm()
class MyRCForm extends Component {
? ? constructor(props) {
? ? ? ? super(props);
? ? }
? ? componentDidMount() {
? ? ? ? const { setFieldsValue } = this.props.form;
? ? ? ? setFieldsValue({
? ? ? ? ? ? username: "default"
? ? ? ? });
? ? }
? ? submit = () => {
? ? ? ? const { getFieldsValue, getFieldValue } = this.props.form;
? ? ? ? console.log("syta", getFieldsValue(), getFieldValue("username")); // sy-log
? ? }
? ? render() {
? ? ? ? console.log("props", this.props);
? ? ? ? const { getFieldDecorator } = this.props.form;
? ? ? ? return (
? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? <h3>MyRCForm</h3>
? ? ? ? ? ? ? ? {getFieldDecorator("username", {rules: [nameRules]})(<Input
? ? ? ? ? ? ? ? ? ? placeholder="Username"
? ? ? ? ? ? ? ? />)}
? ? ? ? ? ? ? ? {getFieldDecorator("password", {rules: [passwordRules]})(<Input
? ? ? ? ? ? ? ? ? ? placeholder="Password"
? ? ? ? ? ? ? ? />)}? ? ?
? ? ? ? ? ? ? ? <button onClick={this.submit}>submit</button>
? ? ? ? ? ? </div>
? ? ? ? )
? ? }
}
export default MyRCForm
打印結(jié)果如下:
3.自定義一個(gè)高階組件createForm:
MyRCForm.js文件內(nèi)容如下:
import React, { Component } from 'react';
import Input from '../components/Input';
import { createForm } from '../components/my-rc-form/index';
const nameRules = {required: true, message: "請(qǐng)輸入姓名制圈!"};
const passwordRules = {required: true, message: "請(qǐng)輸入密碼!"};
@createForm
class MyRCForm extends Component {
? ? constructor(props) {
? ? ? ? super(props);
? ? }
? ? componentDidMount() {
? ? ? ? const { setFieldsValue } = this.props.form;
? ? ? ? setFieldsValue({
? ? ? ? ? ? username: "李明",
? ? ? ? ? ? password: "123"
? ? ? ? });
? ? }
? ? submit = () => {
? ? ? ? const { getFieldsValue, getFieldValue, validateFields } = this.props.form;
? ? ? ? console.log("syta", getFieldsValue(), getFieldValue("username")); // sy-log
? ? ? ? validateFields((err, vals) => {
? ? ? ? ? ? if(err) {
? ? ? ? ? ? ? ? console.log("失敗", err)
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? console.log("成功", vals)
? ? ? ? ? ? }
? ? ? ? })
? ? }
? ? render() {
? ? ? ? console.log("props", this.props);
? ? ? ? const { getFieldDecorator } = this.props.form;
? ? ? ? return (
? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? <h3>MyRCForm</h3>
? ? ? ? ? ? ? ? {getFieldDecorator("username", {rules: [nameRules]})(<Input
? ? ? ? ? ? ? ? ? ? placeholder="Username"
? ? ? ? ? ? ? ? />)}
? ? ? ? ? ? ? ? {getFieldDecorator("password", {rules: [passwordRules]})(<Input
? ? ? ? ? ? ? ? ? ? placeholder="Password"
? ? ? ? ? ? ? ? />)}
? ? ? ? ? ? ? ? <button onClick={this.submit}>submit</button>
? ? ? ? ? ? </div>
? ? ? ? )
? ? }
}
export default MyRCForm
components/my-rc-form/index.js文件內(nèi)容如下:
import React, { Component } from 'react'
export function createForm(Cmp) {
? ? return class extends Component {
? ? ? ? constructor(props) {
? ? ? ? ? ? super(props);
? ? ? ? ? ? this.state = {}
? ? ? ? ? ? this.options = {}
? ? ? ? }
? ? ? ? getFieldsValue = () => {
? ? ? ? ? ? return {...this.state};
? ? ? ? }
? ? ? ? getFieldValue = (name) => {
? ? ? ? ? ? return this.state[name];
? ? ? ? }
? ? ? ? setFieldsValue = (newStore) => {
? ? ? ? ? ? this.setState(newStore)
? ? ? ? }
? ? ? ? handleChange = (e) => {
? ? ? ? ? ? const { name, value } = e.target;
? ? ? ? ? ? this.setState({
? ? ? ? ? ? ? ? [name]: value
? ? ? ? ? ? }, () => {
? ? ? ? ? ? ? ? console.log("state", this.state);
? ? ? ? ? ? })
? ? ? ? }
? ? ? ? getFieldDecorator = (fieldName, option) => InputCmp => {
? ? ? ? ? ? this.options[fieldName] = option;
? ? ? ? ? ? return React.cloneElement(InputCmp, {
? ? ? ? ? ? ? ? name: fieldName,
? ? ? ? ? ? ? ? value: this.state[fieldName] || "",
? ? ? ? ? ? ? ? onChange: this.handleChange
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? validateFields = (callback) => {
? ? ? ? ? ? let err = [];
? ? ? ? ? ? for(let fieldName in this.options) {
? ? ? ? ? ? ? ? if(!this.state[fieldName]) {
? ? ? ? ? ? ? ? ? ? err.push({
? ? ? ? ? ? ? ? ? ? ? ? [fieldName]: "err"
? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? if(err.length === 0) {
? ? ? ? ? ? ? ? callback(null, {...this.state});
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? callback(err, {...this.state});
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? getForm = () => {
? ? ? ? ? ? return {
? ? ? ? ? ? ? ? getFieldsValue: this.getFieldsValue,
? ? ? ? ? ? ? ? getFieldValue: this.getFieldValue,
? ? ? ? ? ? ? ? setFieldsValue: this.setFieldsValue,
? ? ? ? ? ? ? ? getFieldDecorator: this.getFieldDecorator,
? ? ? ? ? ? ? ? validateFields: this.validateFields
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? render() {
? ? ? ? ? ? const form = this.getForm();
? ? ? ? ? ? return (
? ? ? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? ? ? <Cmp {...this.props} form={form}/>
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? )
? ? ? ? }
? ? }
}
打印結(jié)果如下:
注意:antd3 的設(shè)計(jì)有個(gè)問(wèn)題畔况,就是局部變化會(huì)引起整體變化鲸鹦,即每次輸入框的值發(fā)生變化的時(shí)候,會(huì)重新渲染頁(yè)面跷跪,比較消耗性能馋嗜,不過(guò) antd4 改進(jìn)了這個(gè)問(wèn)題。