react难点

高阶组件

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>
    );
  }
}

表单组件装饰器用法 antd提供的

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>
      );
    }
  };
}

实现一个dialog组件 使用传送门portal

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
    );
  }
}

context

  1. Context
  2. redux
  3. redux github


compose实现

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)));
}

你可能感兴趣的:(javascript)