HOC: 是个函数,接收一个组件,返回一个新的组件
function Child(props) {
return <div>Child</div>;
}
const foo = Cmp => props => {
return (
<div className="border">
<Cmp {...props} />
</div>
);
};
const Foo = foo(foo(Child)) 可以链式调用
<Foo /> 渲染
高阶函数写的太繁琐了
装饰器安装方法
经过 eject 后在 package.json 中的 plugins 中配置
在babel对象 修改为下面代码
{
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{ "legacy": true }
]
]
}
}
create-react-app 脚手架中已经安装了 @babel/plugin-proposal-decorators 插件,如果是自己配置的脚手架,则先要安装插件:`npm install @babel/plugin-proposal-decorators --save-dev
缺点 : 麻烦
import { Form, Input, Icon, Button } from "antd";
export default class FormPage extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
password: ""
};
}
submit = () => {
console.log("submit", this.state); //sy-log
};
render() {
const { name, password } = this.state;
return (
<div>
<Form>
<Form.Item>
<Input
value={name}
onChange={e =>
this.setState({
name: e.target.value
})
}
/>
</Form.Item>
<Form.Item>
<Input
value={password}
onChange={e =>
this.setState({
password: e.target.value
})
}
/>
</Form.Item>
<Button type="primary" onClick={this.submit}>
提交
</Button>
</Form>
</div>
);
}
}
import { Form, Input, Icon, Button } from "antd";
const nameRules = { required: true, message: "please input ur name" };
const passwordRules = { required: true, message: "please input ur password" };
@Form.create({})
class FormPage2 extends Component {
submit = () => {
const { validateFields, getFieldsValue, getFieldValue } = this.props.form;
validateFields((err, values) => {
if (err) {
console.log("err", err); //sy-log
} else {
console.log("success", values); //sy-log
}
});
console.log("submit", getFieldsValue(), getFieldValue("name")); //sy-log
};
render() {
console.log("props", this.props); //sy-log
const { getFieldDecorator } = this.props.form;
return (
<div>
<Form>
<Form.Item>
{getFieldDecorator("name", { rules: [nameRules] })(
<Input placeholder="please input ur name" />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("password", { rules: [passwordRules] })(
<Input type="password" placeholder="please input ur password" />
)}
</Form.Item>
<Button type="primary" onClick={this.submit}>
提交
</Button>
</Form>
</div>
);
}
}
理解到:@a 去装饰b组件 其实a是一个函数,它的参数是组件b,需要返回一个b组件,
也可以是一个匿名组件内部render b组件
import kFormCreate from "../components/kFormCreate";
const nameRules = {required: true, message: "please input ur name"};
const passwordRules = {required: true, message: "please input ur password"};
@kFormCreate
class MyFormPage extends Component {
submit = () => {
const {getFieldsValue, getFieldValue, validateFields} = this.props;
validateFields((err, values) => {
if (err) {
console.log("err", err); //sy-log
} else {
console.log("success", values); //sy-log
}
});
console.log("submit", getFieldsValue(), getFieldValue("password"));
};
render() {
console.log("props", this.props); //sy-log
const {getFieldDecorator} = this.props;
return (
<div>
{getFieldDecorator("name", {rules: [nameRules]})(
<input type="text" placeholder="please input ur name" />
)}
{getFieldDecorator("password", {rules: [passwordRules]})(
<input type="password" placeholder="please input ur password" />
)}
<button onClick={this.submit}>提交</button>
</div>
);
}
}
export default function kFormCreate(Cmp) {// Cmp => MyFormPage
return class extends Component {
constructor(props) {
super(props);
this.state = {};
this.options = {};
}
handleChange = e => {
let { name, value } = e.target;
this.setState({ [name]: value });
};
getFieldDecorator = (field, option) => {
this.options[field] = option;
return InputCmp => {
return React.cloneElement(InputCmp, {
name: field,
value: this.state[field] || "",
onChange: this.handleChange
});
};
};
getFieldsValue = () => {
return { ...this.state };
};
getFieldValue = field => {
return this.state[field];
};
validateFields = callback => {
// 校验错误信息
const errors = {};
const state = { ...this.state };
for (let name in this.options) {
if (state[name] === undefined) {
// 没有输入,判断为不合法
errors[name] = "error";
}
}
if (JSON.stringify(errors) === "{}") {
// 合法
callback(undefined, state);
} else {
callback(errors, state);
}
};
render() {
return (
<div className="border">
<Cmp
getFieldDecorator={this.getFieldDecorator}
getFieldsValue={this.getFieldsValue}
getFieldValue={this.getFieldValue}
validateFields={this.validateFields}
/>
</div>
);
}
};
}
import Dialog from "../components/Dialog";
export default class DialogPage extends Component {
constructor(props) {
super(props);
this.state = {
showDialog: false
};
}
render() {
const { showDialog } = this.state;
return (
<div>
<button
onClick={() => {
this.setState({ showDialog: !showDialog });
}}>
toggle
</button>
{showDialog && (
<Dialog>
<p>我是一段文本</p>
</Dialog>
)}
</div>
);
}
}
import {createPortal} from "react-dom";
export default class Dialog extends Component {
constructor(props) {
super(props);
const doc = window.document;
this.node = doc.createElement("div");
doc.body.appendChild(this.node);
}
componentWillUnmount() {
window.document.body.removeChild(this.node);
}
render() {
return createPortal(
<div className="dialog">
{this.props.children}
</div>,
this.node
);
}
}
compose 英[kəmˈpəʊz]
function f1(v) {
return 'f1-' + v + '-f1'
}
function f2(v) {
return 'f2-' + v + '-f2'
}
function f3(v) {
return 'f3-' + v + '-f3'
}
var r = f3(f2(f1('demo')))
console.log(r)
var re = compose(f1, f2, f3)('demo')
console.log(re)
function compose(...params) {
return function (...str) {
return params.reduce((accumulator, onec, index) => {
return onec(accumulator)
}, ...str)
}
}
还有一种方法
function compose(...params) {
return params.reduce(
(accumulator, onec) => {
return (...args) => accumulator(onec(...args))
}
)
}
reduce 不传第二个参数则 accumulator是数组第一项,onec从第二项开始直到最后一项,内部函数的返回值就是accumulator后续值
简写为下面
const compose = (...arr) => arr.reduce((a, b) => (...v) => a(b(...v)))
处理极端情况
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
// return () => {};
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((accumu, f) => (...args) => accumu(f(...args)));
}