文章
问答
冒泡
利用react-hook-form实现类似antd的form组件

antd的form组件在做表单的时候是比较方便的。但是如果我们不使用antd而是其他的组件库,比如material-ui这种,没有自带form组件的,就需要自己稍微封装一下。
利用react-hook-form和react hooks的useContext可以实现类似组件。

1.定义一个form-context

import {createContext} from "react";

const formContext = createContext({});
export default formContext

2.编写form组件

import React from "react";
import formContext from "./form-context";

const Form = ({children, control, errors}) => {

    const form = {
        control: control,
        errors: errors
    }

    return <formContext.Provider value={form}>
        <form>
            {children}
        </form>
    </formContext.Provider>
}
export default Form

3.编写form-item

import React, {useContext} from "react";
import {Grid} from "@material-ui/core";
import {createStyles, makeStyles} from "@material-ui/core/styles";
import FormControl from "@material-ui/core/FormControl";
import {Controller, useForm} from "react-hook-form";
import formContext from "../form-context";

const useStyles = makeStyles((theme) =>
    createStyles({
        root: {
            lineHeight: 1.5715,
            marginBottom: 16,
            minHeight: 32
        },
        formItemLabel: {
            textAlign: 'right',
            '& label': {
                position: 'relative',
                display: 'inline-flex',
                alignItems: 'center',
                height: '100%',
                fontSize: 14,
                '& .colon': {
                    '&:after': {
                        content: '":"',
                        position: 'relative',
                        top: -0.5,
                        margin: '0 8px 0 2px'
                    }
                }
            }
        },
        formItemControl: {
            paddingLeft: 8,
            '& .controlText': {
                lineHeight: 1.5715,
                height: 32,
                display: 'flex',
                alignItems: 'center'
            }
        }
    }),
);


const FormItem = ({children, colon, label, name = 'formName', defaultValue, valueText, rules, editing = false}) => {
    const classes = useStyles();
    const {control, errors} = useContext(formContext);
    return <Grid className={classes.root} container>
        <Grid className={classes.formItemLabel} item md={2}>
            <label form={name} className={`${colon ? 'colon' : ''}`}>{label}</label>
        </Grid>
        <Grid className={classes.formItemControl} item md={10}>
            {!editing && <div className={`controlText`}>{valueText}</div>}
            {editing && <FormControl>
                <Controller
                    name={name}
                    control={control}
                    defaultValue={defaultValue}
                    rules={rules}
                    as={children}
                />
            </FormControl>}
        </Grid>
    </Grid>
}
export default FormItem

4.使用

import React from "react";
import FormItem from "../../../../components/form/form-item";
import Input from "@material-ui/core/Input";
import {useForm} from "react-hook-form";
import Form from "../../../../components/form";
import RadioGroup from "@material-ui/core/RadioGroup";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Radio from "@material-ui/core/Radio";
import {Button} from "@material-ui/core";

const BaseInfoForm = ()=>{

    const {control, handleSubmit,  errors} = useForm({

    });

    const handleSave = (values)=>{
        console.log(values)
    }

    return <div>
        <Form control={control} errors={errors}>
            <FormItem label={`真实姓名`} name={`realName`} editing={true}>
                <Input fullWidth inputProps={{'aria-label': 'description'}}/>
            </FormItem>
            <FormItem label={<span>性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;别</span>} name={`gender`} editing={true}>
                <RadioGroup row>
                    <FormControlLabel value="best" control={<Radio  color={'primary'} size="small" />} label="The best!" />
                    <FormControlLabel value="worst" control={<Radio color={'primary'} size="small" />} label="The worst." />
                </RadioGroup>
            </FormItem>
            <Button onClick={handleSubmit(handleSave)}>保存</Button>
        </Form>
    </div>
}
export default BaseInfoForm



界面如下
image4.png
点击保存按钮,控制台打印出

{realName: "1212", gender: "best"}



完成预期

antd
react-hook-form

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读