对 react 中 render props 模式的理解

255 阅读2分钟

官方介绍:

术语 “render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术

具有 render prop 的组件接受一个函数,该函数返回一个 React 元素并调用它而不是实现自己的渲染逻辑。

看了官方的介绍和例子,还是不容易理解, 照着案例写了一遍,大概明白了其中的关系。

render props 模式的目的是实现组件复用(状态 state 和操作state的方法)。

实现方式其实就是利用函数回调传参的方式。

在 Mouse 组件中封装了公共状态(鼠标的坐标),在 MouseTracker 组件中使用的时候,传入一个函数 props, 然后 Mouse 组件在自己内部调用传过来的函数,并将状态作为参数传递给函数,MouseTracker 组件中,就可以拿到需要的状态,然后该函数可以 return 一个任意想要渲染的 UI 结构,而这个返回值又会在 Mouse 组件中调用函数的位置作为结果来渲染。

具体看下面的例子

class Mouse extends React.Component {
  state = {
    x: 0,
    y: 0,
  };

  componentDidMount() {
    window.addEventListener('mousemove', this.handleMouseMove);
  }

  componentWillUnmount() {
    window.removeEventListener('mousemove', this.handleMouseMove);
  }

  handleMouseMove = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY,
    });
  };
  render() {
    // this.props.render 是一个函数
    // 调用函数时将状态传递出去
    // 调用函数之后的结果作为 render 要渲染的UI
    return this.props.render(this.state);
  }
}

在 MouseTracker 中复用鼠标位置状态。

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        {/* point: 形参接收传过来的状态(鼠标位置) */}
        {/* 函数要返回想要渲染的UI,会在调用的地方渲染 */}
        <Mouse
          render={(point) => {
            return (
              <p>
                鼠标当前位置:({point.x}, {point.y})
              </p>
            );
          }}
        />
      </div>
    );
  }
}

如果有其他组件需要使用鼠标位置,类似上面的使用方法即可实现复用。

重要的是要记住,render prop 是因为模式才被称为 render prop ,你不一定要用名为 render 的 prop 来使用这种模式

所以,可以使用 children 代替 render。

    1. 只需要将 Mouse 组件中 this.props.render(this.state) 替换为 this.props.children(this.state)
    1. 使用的时候,不需要添加 render 属性,而是直接将函数写在组件中间。
class Mouse extends React.Component {
  // ...省略的相同部分,具体参考上面示例
  
  render() {
    return this.props.children(this.state);
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <Mouse>
          {/* 要注意使用 children 时,是写在组件中间的 */}
          {(point) => {
            return (
              <p>
                children-props 鼠标当前位置:({point.x}, {point.y})
              </p>
            );
          }}
        </Mouse>
      </div>
    );
  }
}