Re learning react — higher order components

Time:2021-6-4

1、 Advanced component Foundation

In a word: it is a function that passes in a component and returns a new component; The function is to enhance the incoming components

const lessons = [
    {stage: 'react', Title: 'componentization 1'},
    {stage: 'react', Title: 'componentization 2'},
    {stage: 'react', Title: 'componentization 3'}
];

//Function component
function Lesson(props: any) {
    return <div>
        {props.stage} - {props.title}
    </div>;
}


const withContent = (Comp: any) => (props: any) => {
    const content = lessons[props.idx];
    return <Comp {...content}/>;
};
//High order components
const LessonContent = withContent(Lesson);

//High order components的运用
<LessonContent idx={2}/>

In addition, we all know that a syntax in ES6 is called decorator. It is the same for components and high-level components, but decorators can only be used in class components

const withContent2 = (Comp: any) => {
    return class extends React.Component<any, any> {
        render() {
            const content = lessons[this.props.idx];
            return <Comp {...content}/>;
        }
    };
};

@withContent2
class Lesson2Content extends React.Component<any, any> {
    render() {
        return <div>
            {this.props.stage} - {this.props.title}
        </div>;
    }
}
//Application
<Lesson2Content idx={1}/>

2、 Simple implementation of form verification in antd using high level components

1. Let’s look at the usage of antd first

import { Form, Icon, Input, Button } from 'antd/es';

class HorizontalLoginForm extends React.Component {

    handleSubmit = e => {
        e.preventDefault();
        this.props.form.validateFields((err, values) => {
            if (!err) {
                console.log('Received values of form: ', values);
            }
        });
    };

    render() {
        const { getFieldDecorator} = this.props.form;
        return (
            <Form layout="inline" onSubmit={this.handleSubmit}>
                <Form.Item >
                    {getFieldDecorator('username', {
                        rules: [{ required: true, message: 'Please input your username!' }],
                    })(
                        <Input
                            prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
                            placeholder="Username"
                        />,
                    )}
                </Form.Item>
                
                <Form.Item>
                    <Button type="primary" htmlType="submit">
                        Log in
                    </Button>
                </Form.Item>
            </Form>
        );
    }
}

const WrappedHorizontalLoginForm = Form.create({ name: 'horizontal_login' })(HorizontalLoginForm);

2. Let’s implement form. Create

Replace form. Create with kformcreate
(1)

const kFormCreate = (Form: any) => {

    return (props: any) => {
        //State stores the value key value pair Name: value
        const [state, setState] = useState<any>({});
        //Store the existing error information name: errmsg
        const [errMsg, setErrMsg] = useState<any>({});
        //Stores the key value name of the current validation
        const validateKey = useRef('');
        //The validation option name: {rules:[{ required:... , ...}]}
        const options = useRef<any>({});
        
        //Form change event, change state and trigger single item verification
        const handleChange = (e: any) => {
            const {name, value} = e.target;
            //During form change, the key value to be verified is stored
            validateKey.current = name;
            setState((state: any) => ({
                ...state,
                [name]: value
            }));
        };
        
        //Single item verification depends on options and state, but it mainly depends on the change of state, that is, the change of form value. Options can only be changed when the getfileddec method initializes the form (at this time, validatekey. Current is empty, so it can't go into single item verification)
        const validateFiled = useCallback((field: string) => {
            const {rules} = options.current[field];
            const value = state[field];
            const ret = !rules.some((rule: any) => {
                if (rule.required && !value) {
                    setErrMsg((err: any) => ({
                        ...err,
                        [field]: rule.message
                    }));

                    return true;
                }
                return false;
            });

            if (ret) {
                setErrMsg((err: any) => ({
                    ...err,
                    [field]: ''
                }));
            }

            return ret;
        }, [options, state]);


        useEffect(() => {
            //Monitor the change of validatefiled, and check the single item as soon as it changes
            if (validateKey.current) {
                validateFiled(validateKey.current);
            }

        }, [validateFiled]);

        //The incoming validation rule returns a higher-order component
        const getFiledDec = (field: string, option: object) => {
            //Add validation options
            options.current[field] = option;
            
            //High order components
            return (InputComp: any) => {
                return <div>
                    {
                        <!--  Clone the original component to facilitate the rewriting of properties and methods -- >
                        React.cloneElement(InputComp, {
                            name: field,
                            value: state[field] || '',
                            onChange: handleChange
                        })
                    }
                    {
                        <!--  When there is an error, the error message will be displayed -- >
                        !!errMsg[field] && <div style={{color: 'red'}}>{errMsg[field]}</div>
                    }
                </div>;
            };
        };
        
        //Submit verification (overall verification)
        const validateFileds = (cb: (res:any) => {}) => {
            const ret = Object.keys(options.current).every((key: string) => {
                return validateFiled(key);
            });
            if (ret) {
                cb(state);
            }
        };

        return <Form
            {...props}
            getFiledDec={getFiledDec}
            validateFileds={validateFileds}
        >
        </Form>;
    };
};

3. Use

const KForm = (props: any) => {
    const {getFiledDec, validateFileds} = props;
    const onSubmit = () => {
        validateFileds((res: any) => {
            console.log(res);
        });
    };

    return <div>
        {
            getFiledDec('username', {
                rules: [{required: true, message: 'Please input your username!'}]
            })(<Input type="text"/>)
        }
        {
            getFiledDec('password', {
                rules: [{required: true, message: 'Please input password!'}]
            })(<Input type="password"/>)
        }

        < button onclick = {onsubmit} > login < / button >
    </div>;
};

const MyForm = kFormCreate(KForm);

export default () => {
    return <div>
        <MyForm/>
    </div>;
}