一、高阶组件基础
一句话:就是一个函数,传入一个组件,返回一个新组件;作用就是对传入的组件进行了增强
const lessons = [
{stage: 'react', title: '组件化1'},
{stage: 'react', title: '组件化2'},
{stage: 'react', title: '组件化3'}
];
// 函数组件
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}/>;
};
// 高阶组件
const LessonContent = withContent(Lesson);
// 高阶组件的运用
<LessonContent idx={2}/>
另外我们都知道ES6中的一种语法叫做装饰器,用在组件上和高阶组件也是一样的,只不过装饰器只能用在类组件中
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>;
}
}
// 运用
<Lesson2Content idx={1}/>
二、利用高阶组件简单实现antd中的表单验证
1、先看一下antd用法
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、我们实现一下Form.create
用kFormCreate代替Form.create
(1)
const kFormCreate = (Form: any) => {
return (props: any) => {
// state存储value键值对 name: value
const [state, setState] = useState<any>({});
// 存储存在的错误信息 name: errMsg
const [errMsg, setErrMsg] = useState<any>({});
// 存储当前验证的键值 name
const validateKey = useRef('');
// 存储各个键值的验证选项 name: {rules:[{required:..., ...}]}
const options = useRef<any>({});
// 表单change事件,改变state并触发单项校验
const handleChange = (e: any) => {
const {name, value} = e.target;
// 表单change时,存储当前需要验证的键值
validateKey.current = name;
setState((state: any) => ({
...state,
[name]: value
}));
};
// 单项校验,依赖于options, state,但是主要依赖state变化,也就是表单value的变化,而options只有getFiledDec方法初始化表单时改变options(此时validateKey.current为空,因此走不到单项校验里)
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(() => {
// 监控 validateFiled 变化,一但变化就进行单项校验
if (validateKey.current) {
validateFiled(validateKey.current);
}
}, [validateFiled]);
// 传入校验规则返回一个高阶组件
const getFiledDec = (field: string, option: object) => {
// 添加校验选项
options.current[field] = option;
// 高阶组件
return (InputComp: any) => {
return <div>
{
<!-- 克隆原有组件,方便重写属性和方法 -->
React.cloneElement(InputComp, {
name: field,
value: state[field] || '',
onChange: handleChange
})
}
{
<!-- 有错误时,显示错误信息 -->
!!errMsg[field] && <div style={{color: 'red'}}>{errMsg[field]}</div>
}
</div>;
};
};
// 提交校验(整体校验)
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、使用
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}>登录</Button>
</div>;
};
const MyForm = kFormCreate(KForm);
export default () => {
return <div>
<MyForm/>
</div>;
}
系列
重学react——slot
重学react——state和生命周期
重学react——redux
重学react——hooks以及原理
重学react——context/reducer
重学react——router
重学react——高阶组件
build your own react
React——fiber
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。