谈谈React中的Render Props模式


Posted in Javascript onDecember 06, 2018

概述

Render Props模式是一种非常灵活复用性非常高的模式,它可以把特定行为或功能封装成一个组件,提供给其他组件使用让其他组件拥有这样的能力,接下来我们一步一步来看React组件中如何实现这样的功能。

简要介绍:分离UI与业务的方法一直在演进,从早期的mixins,到HOC,再到Render Prop,本文主要对比HOC,谈谈Render Props

1 . 早期的mixins

早期复用业务通过mixins来实现,比如组件A和组件B中,有一些公用函数,通过mixins剥离这些公用部分,并将其组合成一个公用集合,然后将这个集合传递给每个组件调用。

//公有的函数部分
const someMixins={
 printColor(){
 console.log(this.state.color);
 }
 printWeight(){
 console.log(this.state.weight);
 }
}
class Apple extends React.Component{
 //仅仅作为演示,mixins一般是通过React.createClass创建,并且ES6也没有key:value这种写法
 mixins:[someMixins]
 constructor(props){
 super(props);
 this.state={
  color:'red',
  weight:'100g'
 }
 this.printColor=this.printColor.bind(this);
 }
 render(){
 return <div className="m-box" onClick={this.printColor}>
    这是一个苹果
   </div>
 }
}
class Banana extends React.Component{
 mixins:[someMixins]
 constructor(props){
 super(props);
 this.state={
  color:'yellow',
  weight:'200g'
 }
 this.printColor=this.printColor.bind(this);
 }
 render(){
 return <div className="m-box" onClick={this.printColor}>
    这是一个香蕉
   </div>
 }
}

 上述的例子中,Apple和Banana都具有printColor和printWeight方法,通过mixins分离公共业务。mixins已经在React16.0版本移除,这里仅仅做一个介绍。

2 . HOC

HOC简单理解就是组件工厂,接受原始组件作为参数,添加完功能与业务后,返回新的组件。下面来介绍HOC参数的几个例子。

(1)参数仅为原始组件,比如:

const redApple = withFruit(Apple);

 (2)参数为原始组件和一个对象,比如:

const redApple = withFruit(Apple,{color:'red',weight:'200g'});

但是这种情况比较少用,如果对象中仅仅传递的是属性,其实完全可以通过组件的props实现值的传递,我们用HOC的主要目的是分离业务,关于UI的展示,以及一些组件中的属性和状态,我们一般通过props来指定比较方便

(3)参数为原始组件和一个函数,比如:

const redApp=withFruit(App,()=>{console.log('I am a fruit')})

这种是HOC的典型例子,原始组件参数表示UI部分,函数参数表示处理逻辑,在HOC工厂中进行耦合后生成新的组件。

(4)柯里化

最常见的是仅以一个原始组件作为参数,但是在外层包裹了业务逻辑,比如react-redux的conect函数中:

class Admin extends React.Component{

}
const mapStateToProps=(state)=>{
 return {
 };
}
const mapDispatchToProps=(dispatch)=>{
 return {

 }
}

const connect(mapStateToProps,mapDispatchToProps)(Admin)

 这里不是严格的柯里化,但是思想是一样的,在HOC的工厂函数中在包一层父函数,用于指定业务逻辑。

3 . HOC的缺点

下面我们来看看HOC的缺点:

(1)难以溯源,且存在属性覆盖问题

如果原始组件A,先后通过工厂函数1,工厂函数2,工厂函数3….构造,最后生成了组件B,我们知道组件B中有很多与A组件不同的props,但是我们仅仅通过组件B,并不能知道哪个组件来自于哪个工厂函数。同时,如果有2个工厂函数同时修改了组件A的某个同名属性,那么会有属性覆盖的问题,会使得前一个工厂函数的修改结果失效。

(2)HOC是静态构建的

所谓静态构建,也就是说生成的是一个新的组件,并不会马上render,HOC组件工厂是静态构建一个组件,这类似于重新声明一个组件的部分。也就是说,HOC工厂函数里面的声明周期函数,也只有在新组件被渲染的时候才会执行。

(3)会产生无用的空组件

4. 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 {
 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}>

  {/*
   Instead of providing a static representation of what <Mouse> renders,
   use the `render` prop to dynamically determine what to render.
  */}
  {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>
 );
 }
}

上述是官网给出的例子,我们来看主要是部分是下面这两句:

Class Mouse extends React.component{
 ...
 {this.props.render(this.state)}
 ...
}


......
<Mouse render={mouse => (
   <Cat mouse={mouse} />
  )}/>

在使用Mouse组件的时候,通过一个render属性,传递一个可用组件Cat给父组件Mouse,而在Mouse组件中,可以将本身的state对象传递给Cat组件,Cat组件中的mouse属性的值与Mouse父组件中的state相同。

精简来说: 就是父组件可以将自己的state传递给子组件,而子组件可以根据父组件的state对象,来进行render。

这样做的好处是:

(1)不用担心props的命名问题

(2)可以溯源,子组件的props一定是来自于直接父组件

(3)是动态构建的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
(function(){})()的用法与优点
Mar 11 Javascript
Jquery判断$(&quot;#id&quot;)获取的对象是否存在的方法
Sep 25 Javascript
一个简单的动态加载js和css的jquery代码
Sep 01 Javascript
AngularJS入门教程(二):AngularJS模板
Dec 06 Javascript
JavaScript导航脚本判断当前导航
Jul 12 Javascript
jQuery实现最简单的切换图效果【可兼容IE6、火狐、谷歌、opera等】
Sep 04 Javascript
微信小程序 倒计时组件实现代码
Oct 24 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
Dec 05 Javascript
PHP实现记录代码运行时间封装类实例教程
May 08 Javascript
深入理解 webpack 文件打包机制(小结)
Jan 08 Javascript
详解如何创建并发布一个 vue 组件
Nov 08 Javascript
Vue提供的三种调试方式你知道吗
Jan 18 Vue.js
详解Vue-axios 设置请求头问题
Dec 06 #Javascript
超好用的jQuery分页插件jpaginate用法示例【附源码下载】
Dec 06 #jQuery
jQuery动态操作表单示例【基于table表格】
Dec 06 #jQuery
js防抖和节流的深入讲解
Dec 06 #Javascript
angular中两种表单的区别(响应式和模板驱动表单)
Dec 06 #Javascript
微信小程序dom操作的替代思路实例分析
Dec 06 #Javascript
详解Webstorm 下的Angular2.0开发之路(图文)
Dec 06 #Javascript
You might like
判“新”函数:得到今天与明天的秒数
2006/10/09 PHP
php+mysql开源XNA 聚合程序发布 下载
2007/07/13 PHP
PHP笛卡尔积实现算法示例
2018/07/30 PHP
CI框架教程之优化验证码机制详解【验证码辅助函数】
2019/04/16 PHP
php输出反斜杠的实例方法
2019/09/19 PHP
document.body.scrollTop 值总为0的解决方法 比较常见的标准问题
2009/11/30 Javascript
DOM基础教程之使用DOM设置文本框
2015/01/20 Javascript
Bootstrap实现带动画过渡的弹出框
2016/08/09 Javascript
js从数组中删除指定值(不是指定位置)的元素实现代码
2016/09/13 Javascript
jquery对象和DOM对象的相互转换详解
2016/10/18 Javascript
用Vue.js实现监听属性的变化
2016/11/17 Javascript
使用 Node.js 模拟滑动拼图验证码操作的示例代码
2017/11/02 Javascript
通过一次报错详细谈谈Point事件
2018/05/17 Javascript
微信小程序实现左右联动的实战记录
2018/07/05 Javascript
[02:46]2014DOTA2国际邀请赛 选手为你解读比赛MVP充满梦想
2014/07/09 DOTA
在Python的Django框架中生成CSV文件的方法
2015/07/22 Python
Python中的异常处理相关语句基础学习笔记
2016/07/11 Python
利用python模拟sql语句对员工表格进行增删改查
2017/07/05 Python
python爬虫headers设置后无效的解决方法
2017/10/21 Python
python针对excel的操作技巧
2018/03/13 Python
kaggle+mnist实现手写字体识别
2018/07/26 Python
浅谈Python中的bs4基础
2018/10/21 Python
pandas ix &amp;iloc &amp;loc的区别
2019/01/10 Python
Windows 安装 Anaconda3+PyCharm的方法步骤
2019/06/13 Python
Python的scikit-image模块实例讲解
2020/12/30 Python
代理协议书
2014/04/22 职场文书
面试自我介绍演讲稿
2014/04/29 职场文书
加强干部作风建设整改方案
2014/10/24 职场文书
2014财务年终工作总结
2014/12/08 职场文书
车辆管理制度范本
2015/08/05 职场文书
创业方案:赚钱的烧烤店该怎样做?
2019/07/05 职场文书
Nginx域名转发使用场景代码实例
2021/03/31 Servers
golang 如何用反射reflect操作结构体
2021/04/28 Golang
Python包argparse模块常用方法
2021/06/04 Python
基于JavaScript实现年月日三级联动
2021/06/22 Javascript
一篇文章了解正则表达式的替换技巧
2022/02/24 Javascript