Skip to content

装饰器 ​

本节目标:理解“装饰器”的核心思路,并能把它用于实际开发或面试表达。 cra支持装饰器

安装npm i react-app-rewired customize-cra @babel/plugin-proposal-decorators -D

修改

package.json
  "scripts": {    "start": "react-app-rewired start",    "build": "react-app-rewired build",    "test": "react-app-rewired test",    "eject": "react-app-rewired eject"  }
config-overrides.js
const {override,addBabelPlugin} = require('customize-cra');
module.exports = override(  addBabelPlugin( [    "@babel/plugin-proposal-decorators", { "legacy": true }  ]))
jsconfig.json
{  "compilerOptions": {     "experimentalDecorators": true  }}

属性代理

  • 基于属性代理:操作组件的props
import React from 'react';import ReactDOM from 'react-dom';const loading = message =>OldComponent =>{    return class extends React.Component{        render(){            const state = {                show:()=>{                    let div = document.createElement('div');                    div.innerHTML = `<p id="loading" style="position:absolute;top:100px;z-index:10;background-color:black">${message}</p>`;                    document.body.appendChild(div);                },                hide:()=>{                    document.getElementById('loading').remove();                }            }            return  (                <OldComponent {...this.props} {...state} {...{...this.props,...state}}/>            )        }    }}@loading('

正在加载中

')class Hello extends React.Component{  render(){     return <div>hello<button onClick={this.props.show}>show</button><button onClick={this.props.hide}>hide</button></div>;  }}let LoadingHello  = loading('

正在加载

')(Hello);
ReactDOM.render(    <LoadingHello/>, document.getElementById('root'));

反向继承

  • 基于反向继承:拦截生命周期、state、渲染过程
import React from 'react';import ReactDOM from 'react-dom';class Button extends React.Component{    state = {name:'

张三

'}    componentWillMount(){        console.log('Button componentWillMount');    }    componentDidMount(){        console.log('Button componentDidMount');    }    render(){        console.log('Button render');        return <button name={this.state.name} title={this.props.title}/>    }}const wrapper = OldComponent =>{    return class NewComponent extends OldComponent{        state = {number:0}        componentWillMount(){            console.log('WrapperButton componentWillMount');             super.componentWillMount();        }        componentDidMount(){            console.log('WrapperButton componentDidMount');             super.componentDidMount();        }        handleClick = ()=>{            this.setState({number:this.state.number+1});        }        render(){            console.log('WrapperButton render');            let renderElement = super.render();            let newProps = {                ...renderElement.props,                ...this.state,                onClick:this.handleClick            }            return  React.cloneElement(                renderElement,                newProps,                this.state.number            );        }    }}let WrappedButton = wrapper(Button);ReactDOM.render(    <WrappedButton title="

标题

"/>, document.getElementById('root'));
src\react.js
import { wrapToVdom } from "./utils";import { Component } from './Component';import { REACT_FORWARD_REF_TYPE, REACT_CONTEXT, REACT_PROVIDER } from './constants';function createElement(type, config, children) {  let ref;  let key;  if (config) {    delete config.__source;    delete config.__self;    ref = config.ref;    delete config.ref;    key = config.key;    delete config.key;  }  let props = { ...config };  if (arguments.length > 3) {    props.children = Array.prototype.slice.call(arguments, 2).map(wrapToVdom);  } else {    props.children = wrapToVdom(children);  }  return {    type,    ref,    key,    props,  };}function createRef() {  return { current: null };}function forwardRef(render) {  var elementType = {    $$typeof: REACT_FORWARD_REF_TYPE,    render: render  };  return elementType;}function Fragment(props) {  return props.children;}function createContext() {  let context = { $$typeof: REACT_CONTEXT };  context.Provider = {    $$typeof: REACT_PROVIDER,    _context: context  }  context.Consumer = {    $$typeof: REACT_CONTEXT,    _context: context  }  return context;}+function cloneElement(element, newProps, ...newChildren) {+  let oldChildren = element.props && element.props.children;+  let children = [...(Array.isArray(oldChildren) ? oldChildren : [oldChildren]), ...newChildren]+    .filter(item => item !== undefined)+    .map(wrapToVdom);+  if (children.length === 1) children = children[0];+  let props = { ...element.props, ...newProps, children };+  return { ...element, props };+}const React = {  createElement,  Component,  createRef,  forwardRef,  Fragment,  createContext,+ cloneElement};export default React;

本站总访问 — 次