React模式 - Render Props

在React官方的高级指南中有个Render Props模式,这个模式在写可复用的组件时可能会被用到。那么什么是Render Props模式呢?

Render Props是指一种通过传递函数作为属性来分享组件中数据的技术

Render Props

接下来讲以官方的一个例子来说明。

首先我们有一个组件<Mouse>,内部有当前鼠标位置的数据

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

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

  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>

        {/* ...but how do we render something other than a <p>? */}
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </div>
    );
  }
}
复制代码

接下来要创建一个组件<Cat>,<Cat>需要使用鼠标位置信息来更新自身位置,完成鼠标随动的功能。

这么问题就来了,我们要怎么利用<Mouse>类来完成这一功能。

首先最简单的就是直接在<Mouse>类中引入<Cat>, 再把数据传递到<Cat>中

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

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

 render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <Cat mouse={this.state} />
      </div>
    );
  }
}
复制代码

这样我们创建了新了组件<MouseWithCat>,这种方式可以实现功能,但是并没有对<Mouse>进行有效的复用,如果后续有其他需要使用鼠标位置信息的组件,那么我们也要创建一个新的组件。

为了更好的复用<Mouse>组件,我们可以使用Render Props模式。直接看例子:

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}

class Mouse extends React.Component {
    // 省略部分代码
    render() {
        return (
            <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
                {this.props.render(this.state)}
            </div>
        );
    }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}
复制代码

可以看到,<Mouse>进行了重构,让其可以接受一个属性,属性的类型为函数,然后在render阶段去执行这个函数,并把相应的内部参数传递进去。

在使用时,传给render属性一个函数,函数返回<Cat>, 并把函数参数传递给了<Cat>属性。这样我们也完成上述要求的功能,同时如果有其他需要用到鼠标信息的组件,我们都可以复用<Mosue>组件,而不用像之前一样去创建新的组件。

讲完这个例子,我们可以看到Render Props模式的优势所在,它让我们有效的编写可复用的组件

高阶组件

这边也可以编写高阶组件来完成功能。

const WithMouse = (component) => {
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.handleMouseMove = this.handleMouseMove.bind(this);
            this.state = { x: 0, y: 0 };
        }

        handleMouseMove(event) {
            this.setState({
                x: event.clientX,
                y: event.clientY
            });
        }
        render() {
            return (
                <component {...this.props} mouse={this.state} />
             )
        }
  }
} 
复制代码

高阶函数同样也可以完成这个功能,但是灵活性会稍微有些降低,使用Render Props的话,我们可以在那个函数中做一些其他操作而不用改动<Mosue>和<Cat>。

Context

React Context新API中也用到了Render Props,在Consumer中需要传递一个函数来消费数据。

import React, {Component} from 'react'
const ThemeContext = React.createContext('light')

class App extends Component {
  render () {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    )
  }
}

function Toolbar () {
  return (
    <div>
      <ThemeButton />
    </div>
  )
}

function ThemeButton (props) {
  return (
    <ThemeContext.Consumer>
      { theme => <button {...props} theme={theme}>{theme}</button> }
    </ThemeContext.Consumer>
  )
}
复制代码

总结

React的Render Props还是比较容易理解的,重点是如何在组件的代码中正确的使用。

最后推荐一篇相关的文章:React's Render Props Pattern - Children as a Function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值