React系列之一块儿认识Render Prop

1.mixins

写过react项目的应该都碰到过,不一样组件复用相同代码的问题,在react早期使用React.createClass建立组件的时代,咱们常用的是mixins来实现代码复用。好比有个组件A,它用来实时的获取鼠标的位置。react

//A组件
import React from 'react'
import ReactDOM from 'react-dom'

const App = React.createClass({
  getInitialState() {
    return { x: 0, y: 0 }
  },

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

  render() {
    const { x, y } = this.state

    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>The mouse position is ({x}, {y})</h1>
      </div>
    )
  }
})

ReactDOM.render(<App/>, document.getElementById('app'))

若是此时有个组件B也想集成这个功能,咱们能够经过mixins,代码是这样的git

//B组件
import React from 'react'
import ReactDOM from 'react-dom'

const MouseMixin = {
  getInitialState() {
    return { x: 0, y: 0 }
  },

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

const App = React.createClass({
  // Use the mixin!
  mixins: [ MouseMixin ],
  
  render() {
    const { x, y } = this.state

    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>The mouse position is ({x}, {y})</h1>
      </div>
    )
  }
})

ReactDOM.render(<App/>, document.getElementById('app'))

很容易是吧~但委屈的是react16以后就再也不支持mixins了,由于es6普及了呀!es6


那怎么办呢?办法老是有的,HOC(高阶组件)的概念被提出来,什么是高阶组件?说白了其实就是把函数当作参数传入到另外一个函数中,在咱们展开高阶组件前,咱们先来想一想除了由于es6的普及react再也不支持mixins以外,mixins还有啥其它缺点不。固然是有的,有如下几点:github

  1. 难以溯源,mixins修改state,在组件内部你没法知道state从哪来,尤为是有多个mixins的状况。
  2. 命名空间,多个mixins修改同一个state致使的命名冲突。

2.HOC(高阶组件)

因此为了代替mixins,不少人就提出了HOC(高阶组件),代码是下面这样的。react-router

import React from 'react'
import ReactDOM from 'react-dom'

const withMouse = (Component) => {
  return class extends React.Component {
    state = { x: 0, y: 0 }

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

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

class App extends React.Component{
    render() {
      // 代替直接处理state,咱们从props里得到x,y坐标
      const { x, y } = this.props.mouse

      return (
        <div style={{ height: '100%' }}>
            <h1>The mouse position is ({x}, {y})</h1>
        </div>
      )
    }
}

//把App组件当作参数传到withMouse方法里面,在withMouse内部经过props得到x、y坐标值
const AppWithMouse = withMouse(App)

ReactDOM.render(<AppWithMouse/>, document.getElementById('app'))

看起来很不错的样子!app


可是,回到以前mixins存在的问题,咱们想想,HOC有上述的问题么?咱们来看下:<br/>dom

  1. 难以溯源,跟mixins不一样的是,咱们再也不纠结state的源头,咱们如今要纠结的是HOC的props里提供了些啥...
  2. 命名空间的冲突,这个问题依然存在,props里属性名可能会被多个HOC重复使用。

个人天.....函数

3.Render Prop

幸运女神降临!
mmp,前面都是炮灰,到了划重点的时候啦!<br/>学习

Render Prop是个值为函数的属性,经过Render Prop,组件知道什么应该被渲染

很糊涂是否是,看代码ui

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

class Mouse extends React.Component {
  static propTypes = {
    render: PropTypes.func.isRequired
  }

  state = { x: 0, y: 0 }

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

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

const App = React.createClass({
  render() {
    return (
      <div style={{ height: '100%' }}>
        <Mouse render={({ x, y }) => (
          <h1>The mouse position is ({x}, {y})</h1>
        )}/>
      </div>
    )
  }
})

ReactDOM.render(<App/>, document.getElementById('app'))

看明白了么,这里咱们经过定义一个render属性,值是个函数,描述了咱们想要渲染的元素,而后在子组件里面调用该render方法,再回头看下以前的两个问题,难以溯源,如今主动权在父组件上,我要什么数据大家给我拿来就好了,大家子组件各自去实现,我只要结果不要过程,于是就不存在数据来源问题,命名空间的问题也没了。好厉害~~~。
最后偷偷的告诉大家一个更厉害的,上面的render方法里面咱们是直接写出了渲染x,y值,只适用于当前App组件,咱们能够经过高阶组件来达到为任何组件添加该功能,代码是这样的。

const withMouse = (Component) => {
    return class extends React.Component{
        render() {
            return <Mouse render={mouse=>(
                <Component {...this.props} mouse={mouse}/>
            )}/>
        }
    }
}

听说react-router源码里面为每一个组件增长路由属性就是经过该方法!

好了!大功完成了,欢迎一块儿讨论学习~

我的博客地址:意卿

相关文章
相关标签/搜索