高阶组件、RenderProps、传送门、插槽、数据渲染优化

72 阅读2分钟

高阶组件

封装一个名为 withAuthentication 的 HOC,它可以在需要进行身份验证的组件中注入认证逻辑。这样,当我们某个组件需要身份验证才能访问的时候,我们就不需要重复编写认证逻辑了。

import React from 'react';

// 1. 定义一个高阶组件 withAuthentication
function withAuthentication(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        isAuthenticated: false
      };
    }

    componentDidMount() {
      // 模拟身份验证逻辑
      setTimeout(() => {
        this.setState({ isAuthenticated: true });
      }, 2000);
    }

    render() {
      const { isAuthenticated } = this.state;
      // 根据身份验证状态进行渲染
      return isAuthenticated ? (
        <WrappedComponent {...this.props} />
      ) : (
        <div>Loading...</div>
      );
    }
  };
}

// 2. 封装需要进行身份验证的组件
class ProtectedComponent extends React.Component {
  render() {
    return <div>Protected content</div>;
  }
}

// 3. 使用 withAuthentication HOC 对 ProtectedComponent 进行保护
const AuthProtectedComponent = withAuthentication(ProtectedComponent);

// 4. 在应用中使用 AuthProtectedComponent
function App() {
  return (
    <div>
      <h1>My App</h1>
      <AuthProtectedComponent />
    </div>
  );
}

RenderProps 技术模式

在 React 中,Render Props 是一种技术模式,用于通过组件的 prop 传递函数,从而实现组件之间的代码共享和逻辑复用。使用 Render Props 可以让组件变得更灵活和可配置

运用场景:封装一个名为 MouseTracker 的组件,它可以追踪鼠标的位置,并将当前鼠标的坐标传递给它的子组件进行显示。这样,每当我们需要在某个组件中跟踪鼠标位置的时候,只需要调用这个 MouseTracker 组件即可。

MouseTracker 封装

class MouseTracker extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      x: 0,
      y: 0
    };
  }

  handleMouseMove = event => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  };

  render() {
    return (
      <div style={{ height: '100vh' }} onMouseMove= {this.handleMouseMove}>
        {this.props.render(this.state)}
      </div>
    );
  }
}

class App extends React.Component {
  render() {
    return (
      <MouseTracker
        render={({ x, y }) => (
          <div>
            <h1>在这里移动鼠标!</h1>
            <p>当前鼠标位置: {x}, {y}</p>
          </div>
        )}
      />
    );
  }
}

在组件中复用 MouseTracker 能力

import React, { Component } from "react";
import MouseTracker from "./MouseTracker";
export default class CompA extends Component {
  render() {
    return (
      <MouseTracker
        render={({ x, y }) => (
          <div>
            一个组件(具备自己的功能)
            <h3>鼠标x坐标:{x}</h3>
            <h3>鼠标y坐标:{y}</h3>
          </div>
        )}
      />
    );
  }
}

Fragment和空标签

  • 只能有一个唯一根节点
  • Fragment 可以包裹内容,但是不会被渲染为真实 DOM 节点
  • 也可以使用空标签代替 Fragment,来实现组件根节点不被渲染为真实 DOM 的效果

props.children插槽

ReactDOM.createPortal()传送门

普通的组件,子组件的元素将挂载到父组件的 DOM 节点中。

有时需要将元素渲染到 DOM 中的不同位置上去,这是就用到的 portal 的方法。

import React, { Component } from "react";
import ReactDOM from "react-dom";
class Modal extends Component {
  render() {
    return ReactDOM.createPortal(
      <div
        style={{
          position: "fixed",
          top: 0,
          right: 0,
          bottom: 0,
          left: 0,
          backgroundColor: "rgba(0, 0, 0, 0.5)",
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <div
          style={{
            width: "50%",
            minHeight: 500,
            backgroundColor: "#fff",
          }}
        >
          <header>
            {this.props.header}
            <span
              style={{ float: "right" }}
              onClick={() => this.props.onClose()}
            >
              ×
            </span>
          </header>
          <div>{this.props.content}</div>
        </div>
      </div>,
      document.getElementsByTagName("body")[0]
    );
  }
}

class App extends Component {
  state = {
    show: false,
  };
  render() {
    return (
      <div>
        <button onClick={() => this.setState({ show: true })}>
          打开模态框
        </button>
        {this.state.show ? (
          <Modal
            header="模态框标题"
            content="这里是一个自定义的模态框"
            onClose={() => this.setState({ show: false })}
          />
        ) : null}
      </div>
    );
  }
}

export default App;
  • 一个 portal 的典型用例是当父组件有 overflow: hiddenz-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框:

getDerivedStateFromProps优化渲染性能

  • 变化时才执行
import React, { Component } from "react";

export default class Test extends Component {
  state = {
    msg: "",
    reMsg: "",
  };
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.msg != prevState.msg) {
      console.log("反转字符串");
      return {
        reMsg: nextProps.msg.split("").reverse().join(""), //保证反转字符串运算,只有在msg发生变化的时候才会执行
        msg: nextProps.msg,
      };
    }
    return null; //代表不更新当前组件的state
  }
  render() {
    return <div>Test,{this.state.reMsg}</div>;
  }
}

PureComponent

  • 使用,识别数据是否发生变化