render属性可以实现组件之间共享代码,值是一个函数,返回一个有自身渲染逻辑的组件,结构一般如下

<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

举个栗子

比如我们有一个 Cat 组件,监听鼠标xy并展示

class Cat extends React.Component {
  render() {
    const { mouse } = this.props
    return (
      <div>{ mouse.x }-{ mouse.y }</div>
    )
  }
}

MouseWithCat 组件监听鼠标的变化并将状态传递给 Cat

class MouseWithCat extends React.Component {
  state = {
    x: 0,
    y: 0
  }
  handleMouseMove = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }
  render() {
    return (
      <div style={{ width: 400, height: 400, border: '1px solid #e5e5e5' }} onMouseMove={ this.handleMouseMove }>
        <Cat mouse={ this.state } />
      </div>
    )
  }
}

这样看起来没什么问题,但是如果来了一个新的 Dog 组件,也需要实现同样的功能,那么就需要再写一遍

class MouseWithDog extends React.Component {
  state = {
    x: 0,
    y: 0
  }
  handleMouseMove = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }
  render() {
    return (
      <div style={{ width: 400, height: 400, border: '1px solid #e5e5e5' }} onMouseMove={ this.handleMouseMove }>
        <Dog mouse={ this.state } />
      </div>
    )
  }
}

以此类推,如果所需要的场景增多了,就会产生大量重复代码,于是 render 属性派上用场了,我们可以通过传递一个函数来决定渲染什么子组件,我们先把 Mouse 组件改变一下,通过调用父级传递的render方法来传递自身的state

class Mouse extends React.Component {
  state = {
    x: 0,
    y: 0
  }
  handleMouseMove = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    })
  }
  render() {
    return (
      <div style={{ width: 400, height: 400, border: '1px solid #e5e5e5' }} onMouseMove={ this.handleMouseMove }>
        {/* 调用props传递的render方法 */}
        { this.props.render(this.state) }
      </div>
    )
  }
}

class MouseTrack extends React.Component {
  render() {
    return (<Mouse render={ mouse => (<Cat mouse={ mouse } />) }/>)
  }
}

这时候如果新增一个 Dog,Pig 都没问题,直接调用就行了

class MouseTrack extends React.Component {
  render() {
    {/* return (<Mouse render={ mouse => (<Pog mouse={ mouse } />) }/>) */}
    return (<Mouse render={ mouse => (<Dog mouse={ mouse } />) }/>)
  }
}

总结

render属性的值是一个函数,通过函数可以传参来动态实现需要渲染的组件

当然我们还可以用高阶组件来实现组件功能的复用,高阶组件的定义是通过包裹(wrapped)被传入的React组件,经过一系列处理,最终返回一个相对增强(enhanced)的React组件,供其他组件调用

声明一个 WithMouse 的高阶组件

import Mouse from './Mouse'
import React from 'react'
export default function WithMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <Mouse render={ (mouse) => (<Component {...this.props} mouse={mouse} />) } />
      )
    }
  }
}

在定义 Cat 组件的时候通过 WithMouse 高阶函数来增加 Cat 的功能

import React from 'react'
import WithMouse from './WithMouse'
class Cat extends React.Component {
  render() {
    const { mouse } = this.props
    return (
      <div>{ mouse.x }-{ mouse.y }</div>
    )
  }
}
export default WithMouse(Cat)