React中的render props,让组件复用(共享)变得简单,你还不赶紧掌握它?

术语“render prop”是指一种在react组件之间使用一个值为函数的prop共享代码的简单技术。

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

我们知道,组件是 React 代码复用的主要单元,但如何分享一个组件封装到其他需要相同 state 组件的状态或行为并不总是很容易。

如何使用render prop?

官网举了一个经典的跟踪 Web 应用程序中的鼠标位置的例子:

Render Props – React

我这里也举一个非常简单的使用render prop的例子,帮助大家更容易去理解。

首先,新建一个显示“Hello World”的组件ShowHello.js:

import React from 'react';

class ShowHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      greet:"Hello World"
    }
  }
  render(){
    return (
      <p>{this.state.greet}</p>
    )
  }
}

export default ShowHello

现在我们有一个组件Page,想要获取组件ShowHello的greet此时的状态(即“Hello World”),我们常规的做法可以是:在ShowHello组件内部的渲染方法渲染 Page组件:

Page.js

import React from 'react';

class Page extends React.Component {
  constructor(props) {
	super(props);
    this.state = {
      greet: this.props.greet     //获取父组件(ShowHello)的prop
    }
  }
  render(){
    return (
      <div>
        <p>{this.state.greet}</p>     //渲染
      </div>
    )
  }
}

export default Page

ShowHello.js

import React from 'react';
import Page from './Page';

class ShowHello extends React.Component {
  constructor(props) {
	super(props);
    this.state = {
      greet:"Hello World"
    }
  }
  render(){
    return (
      <div>
        <Page greet={this.state.greet} />     //将greet作为prop传给子组件Page
      </div>
    )
  }
}

export default ShowHello

这种方法适用于我们的特定用例,但我们还没有达到以可复用的方式真正封装状态或行为的目标。现在,每当我们想要状态用于不同的用例时,我们必须创建一个新的组件(本质上是另一个ShowHello组件,通过将prop传给另一个子组件),它专门为该用例呈现一些东西。

这也是 render prop 的来历:我们可以提供一个带有函数 prop 的ShowHello组件,它能够动态决定什么需要渲染,而不是将Page组件硬编码到ShowHello组件里,并有效地改变它的渲染结果。

import React from 'react';

class ShowHello extends React.Component {
  constructor(props) {
	super(props);
    this.state = {
      greet:"Hello World"
    }
  }
  render(){
    return (
      <div>
        {/* <Page greet={this.state.greet} /> */}   //将prop方式换成render prop的方式
        {this.props.render(this.state.greet)}    //不同的组件共享同一个状态,且不需要创建            
                                                 //一个新的ShowHello组件
      </div>
    )
  }
}

export default ShowHello
import React from 'react';
import ShowHello from './ShowHello';
import Page from './Page';

class Home extends React.Component {
  render(){
    return (
      <div>
        <ShowHello render={greet => (   //通过render prop的方式决定哪个组件渲染使用此状态
          <Page greet={greet}/>
        )}/>
      </div>
    )
  }
}

export default Home

现在,我们提供了一个 render 方法,让ShowHello组件能够动态决定什么需要渲染,而不是克隆ShowHello组件然后硬编码来解决特定的用例。如果存在其他组件使用该状态,那么只需要将render中的Page组件改成其他组件即可。

更具体地说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。

这项技术使我们共享状态或行为非常容易。要获得这个状态或行为,只要渲染一个带有render prop的组件就能够告诉它当前要渲染什么。

render prop并不是react的API,而是一种与高阶组件(HOC)类似的设计模式,ShowHello组件中传递的prop也不一定要是render,也可以是其他标识,如child(或其他自己想要的标识)。

import React from 'react';
import ShowHello from './ShowHello';
import Page from './Page';

class Home extends React.Component {
  render(){
    return (
      <div>
        <ShowHello child={greet => (   //prop可以为自己想要的标识,须传入一个函数
          <Page greet={greet}/>
        )}/>
      </div>
    )
  }
}

export default Home

ShowHello内部的prop也相应变化

import React from 'react';

class ShowHello extends React.Component {
  constructor(props) {
	super(props);
    this.state = {
      greet:"Hello World"
    }
  }
  render(){
    return (
      <div>
        {this.props.child(this.state.greet)}     //prop此时为child,切记此时child为函数
        //上面相当于渲染成 <Page greet={this.state.greet} /> 
      </div>
    )
  }
}

export default ShowHello

更容易理解的一种方式是,你可以认为现在prop传的不是具体某个状态,而是一个函数,函数体是要渲染(或者说使用共享状态)的组件,函数的参数为实际的传入渲染组件的state。

关键部分

<ShowHello child={greet => (  //prop为一个函数
  <Page greet={greet}/>
)}/>
{this.props.child(this.state.greet)}    //为函数传入共享状态

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>