简介

一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术
可以分享一个组件封装到其他需要相同state组件的状态或行为。

示例

我们要监听某一个组件中的鼠标位置。
我们可以使用监听事件 拿到事件对象并获取其中的位置信息。

class MousePosition extends Component {
constructor(props) {
  super(props);
  this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
  this.setState({
    x: event.clientX,
    y: event.clientY
  });
}
render() {
  const {x,y} = this.state;
  return (
    <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
      <p>当前的鼠标位置是 ({x}, {y})</p>
    </div>
  );
}
}

初步需求

要求添加一个logo,并跟随鼠标进行移动。如下
image-20210810170743926.png

解决: 对 logo 使用绝对定位,并将鼠标位置赋给 logo。

class MousePosition extends Component {
constructor(props) {
  super(props);
  this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
  this.setState({
    x: event.clientX,
    y: event.clientY
  });
}
render() {
  const {x,y} = this.state;
  return (
    <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
      <p>当前的鼠标位置是 ({x}, {y})</p>
      <img style={{width:50,height:50,    //<--- +
                position:'absolute',    //<--- +
                left:{x} ,top:{y}}}        //<--- +
                src="/icon.gif" alt="icon" />     //<--- +
    </div>
  );
}

}

增加需求

我们需要在另一个地方使用不同的 logo 达到相同的效果;

方案一:我们可以使用将 img的src 提取为一个变量 imgsrc

class MousePosition extends Component {
constructor(props) {
  super(props);
  this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
  this.setState({
    x: event.clientX,
    y: event.clientY
  });
}
render() {
  const {x,y} = this.state;
  const {imgsrc} = this.props;  //<------     ++++
  return (
    <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
      <p>当前的鼠标位置是 ({x}, {y})</p>
    <img style={{width:50,height:50,
                position:'absolute',
                left : x ,top : y }}
                src={imgsrc} alt="icon" />     //<---  +
    </div>
  );
}
}

然后通过 props 向组件传递一个图片的src。

<MousePosition imgsrc={‘/logo2.gif’}/>

再次增加需求

不在使用图片,而是为鼠标添加注释, 或者还有鼠标滑动效果,或是一些组件等...

这时候就不得不去重新打量这个组件,再次复制一份?这样太抵效了,代码冗余较多。

思考-解决

是否有个即可以传递状态,也可传递组件的属性。所以就该使用 Render Props 来解决问题了。

首先需要将组件划分出来。分为鼠标移动组件与其他需要用到鼠标移动组件中的状态的组件。

鼠标移动组件:

class MousePosition extends Component {
constructor(props) {
  super(props);
  this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
  this.setState({
    x: event.clientX,
    y: event.clientY
  });
}
render() {
  const {x,y} = this.state;
  return (
    <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
      {this.props.render(this.state)}  //使用 this.props.render()将状态渲染出去。
    </div>
  );
}
}

其他组件-图片为例:

export default class Heart extends Component {
  render() {
  const mouse = this.props.mouse;  //设 mouse 为MousePositon渲染出来的 state
  return (
    <div>
      <img style={{width:50,height:50,
          position:'absolute',
          left : mouse.x,top : mouse.y}} 
          src="/icon.gif" alt="icon" />
    </div>
  )
}
}

使用

export default class App extends Component {
render(){
  return (
    <div>
      <MousePosition render={ mouse =>(<Heart mouse={mouse}></Heart>)}/>
  </div>)
}
}

使用 render 属性将渲染出来的 state 命名为 mouse,并以props 的形式传递给 Heart组件。

这样既保证的组件的可复用性。也解决了分享 state 的问题。

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

通俗讲就是可以使用自身的一些状态去渲染一个非自身的元素。

Last modification:August 11th, 2021 at 08:10 pm
如果觉得我的文章对你有用,请随意赞赏