React 基础巩固(二十五)——高阶组件

高阶函数

  • 定义:接收一个或多个函数作为输入输出一个函数 的函数
  • JS 中常用的mapfilterreduce都是高阶函数

高阶组件(Higher-Order Components, HOC)

  • 定义:高阶组件是参数为函数,返回值为新组件的函数
  • 高阶组件本质是函数
  • 高阶组件并不是 React API 的一部分,它是基于 React 的组合特性而形成的设计模式
import React, { PureComponent } from "react";

// 定义一个高阶组件
function hoc(Cpn) {
  // 1.定义一个类组件
  class NewCpn1 extends PureComponent {
    render() {
      return <Cpn />;
    }
  }
  return NewCpn1;
  // 2.定义一个函数组件
  function NewCpn2(props) {}
  return NewCpn2;
}

class HelloWorld extends PureComponent {
  render() {
    return (
      <div>
        <h1>hello world</h1>
      </div>
    );
  }
}

const HelloWorldHOC = hoc(HelloWorld);

export class App extends PureComponent {
  render() {
    return (
      <div>
        <HelloWorld />
        <HelloWorldHOC />
      </div>
    );
  }
}

export default App;

高阶组件的应用场景(一)—— 用户信息增强

  • 构建用户信息增强高阶组件
import React, { PureComponent } from "react";
// 定义组件: 给一些需要特殊数据的组件注入props
function enhanceUserInfo(OriginCmp) {
  class NewComponent extends PureComponent {
    constructor() {
      super();

      this.state = {
        userInfo: {
          name: "outman",
          level: 123,
        },
      };
    }

    render() {
      return <OriginCmp {...this.props} {...this.state.userInfo} />;
    }
  }

  return NewComponent;
}

export default enhanceUserInfo;
  • 使用高阶组件拦截组件并注入用户信息
import React, { PureComponent } from "react";
import enhanceUserInfo from "./enhance_props";

const Home = enhanceUserInfo(function Home(props) {
  return (
    <h1>
      Home: {props.name} - {props.level} - {props.age}
    </h1>
  );
});

const Profile = enhanceUserInfo(function Profile(props) {
  return (
    <h1>
      Profile: {props.name} - {props.level}
    </h1>
  );
});

const Hello = enhanceUserInfo(function Hello(props) {
  return (
    <h1>
      Hello: {props.name} - {props.level}
    </h1>
  );
});

export class App extends PureComponent {
  render() {
    return (
      <div>
        <Home age={"888"} />
        <Profile />
        <Hello />
      </div>
    );
  }
}

export default App;

高阶组件的应用场景(二)—— 拦截并处理Context传参

  • 构建 ThemeContext
import { createContext } from "react";

const ThemeContext = createContext();

export default ThemeContext;
  • 构建 App.jsx,通过 ThemeContext.Provider 传递参数给<Product/>
import React, { PureComponent } from "react";
import ThemeContext from "./context/theme_context";
import Product from "./Product";

export class App extends PureComponent {
  render() {
    return (
      <div>
        <ThemeContext.Provider value={{ color: "red", size: 18 }}>
          <Product />
        </ThemeContext.Provider>
      </div>
    );
  }
}

export default App;
  • 构建 Product.jsx, 在 Product 中,通过 ThemeContext.Consumer 消费参数
import React, { PureComponent } from "react";
import ThemeContext from "./context/theme_context";

// 直接使用上下文方式传递props参数
export class Product extends PureComponent {
  render() {
    return (
      <div>
        Product:
        <ThemeContext.Consumer>
          {(value) => {
            return (
              <h2>
                theme: {value.color} - {value.size}
              </h2>
            );
          }}
        </ThemeContext.Consumer>
      </div>
    );
  }
}

export default Product;
  • 若每次都要采用上述方式,通过ThemeContext.Consumer消费参数,太过繁琐。故,可以利用高阶组件进行处理。
  • 构建高阶组件 with_theme
import ThemeContext from "./theme_context";

function withTheme(OriginComponent) {
  return (props) => {
    return (
      <ThemeContext.Consumer>
        {(value) => {
          return <OriginComponent {...value} {...props} />;
        }}
      </ThemeContext.Consumer>
    );
  };
}

export default withTheme;
  • 通过withTheme包装Product
import React, { PureComponent } from "react";
import withTheme from "./context/with_theme";

// 利用高阶函数方式,更简洁
export class Product extends PureComponent {
  render() {
    const { color, size } = this.props;
    return (
      <div>
        Product:
        {color} - {size}
      </div>
    );
  }
}

export default withTheme(Product);

高阶组件的应用场景(三)—— 登陆鉴权

  • 构建登陆鉴权高阶组件
function loginAuth(OriginComponent) {
  return (props) => {
    // 从localStorage 中获取 token
    const token = localStorage.getItem("token");

    if (token) {
      return <OriginComponent {...props} />;
    } else {
      return <h2>请先登陆</h2>;
    }
  };
}

export default loginAuth;

  • 构建 APP.jsx
import React, { PureComponent } from "react";
import Cart from "./Cart";

export class App extends PureComponent {
  constructor() {
    super();

    this.state = {
      isLogin: false,
    };
  }

  loginClick() {
    localStorage.setItem("token", "test token value");
    this.setState({
      isLogin: true,
    });
  }

  render() {
    const { isLogin } = this.state;

    return (
      <div>
        <button onClick={(e) => this.loginClick()}>登录</button>
        <Cart />
      </div>
    );
  }
}

export default App;

  • 构建Cart.jsx,并用loginAuth包裹Cart进行鉴权处理
import React, { PureComponent } from "react";
import loginAuth from "./login_auth";

export class Cart extends PureComponent {
  render() {
    return (
      <div>
        <h2>Cart</h2>
      </div>
    );
  }
}

export default loginAuth(Cart);

高阶组件的应用场景(四)—— 打印界面渲染时间

  • 构建打印界面渲染时间高阶组件
import { PureComponent } from "react";

function logRenderTime(OriginComponent) {
  return class extends PureComponent {
    UNSAFE_componentWillMount() {
      this.beginTime = new Date().getTime();
    }

    componentDidMount() {
      this.endTime = new Date().getTime();
      const interval = this.endTime - this.beginTime;
      console.log(`当前页面:${OriginComponent.name} 的渲染花费:${interval} ms`);
    }

    render() {
      return <OriginComponent />;
    }
  };
}

export default logRenderTime
  • 构建App.jsx
import React, { PureComponent } from 'react'
import Detail from './Detail'

export class App extends PureComponent {
  render() {
    return (
      <div>
       
        <Detail></Detail>
      </div>
    )
  }
}

export default App

  • 构建Detail.jsx,并通过logRenderTime拦截Detail组件,打印其界面渲染时间
import React, { PureComponent } from "react";
import logRenderTime from "./log_render_time";

export class Detail extends PureComponent {
  render() {
    return (
      <div>
        <h2>Detail Page</h2>
        <ul>
          <li>数据列表1</li>
          <li>数据列表2</li>
          <li>数据列表3</li>
          <li>数据列表4</li>
          <li>数据列表5</li>
          <li>数据列表6</li>
          <li>数据列表7</li>
          <li>数据列表8</li>
          <li>数据列表9</li>
          <li>数据列表10</li>
        </ul>
      </div>
    );
  }
}

export default logRenderTime(Detail);


07-16 06:08