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>性 别</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
界面如下
点击保存按钮,控制台打印出
{realName: "1212", gender: "best"}
完成预期