美文网首页
react render prop

react render prop

作者: Small_Song | 来源:发表于2021-02-26 11:36 被阅读0次

    1.mixins

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

    //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,代码是这样的

    //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普及了呀!

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

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

    2.HOC(高阶组件)

    所以为了代替mixins,很多人就提出了HOC(高阶组件),代码是下面这样的。

    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'))
    
    

    看起来很不错的样子!

    但是,回到之前mixins存在的问题,我们想一想,HOC有上述的问题么?我们来看下:

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

    我的天.....

    3.Render Prop

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

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

    很糊涂是不是,看代码

    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源码里面为每个组件增加路由属性就是通过该方法!

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

    相关文章

      网友评论

          本文标题:react render prop

          本文链接:https://www.haomeiwen.com/subject/ibkuxltx.html