谈谈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 相关文章推荐
用于节点操作的API,颠覆原生操作HTML DOM节点的API
Dec 11 Javascript
ECMAScript 创建自己的js类库
Nov 22 Javascript
caller和callee的区别介绍及演示结果
Mar 10 Javascript
jquery.Ajax()方法调用Asp.Net后台的方法解析
Feb 13 Javascript
javascript教程:关于if简写语句优化的方法
May 17 Javascript
jQuery拖动布局其结果保存到数据库
Oct 09 Javascript
angularjs创建弹出框实现拖动效果
Aug 25 Javascript
jQuery插件之Tocify动态节点目录菜单生成器附源码下载
Jan 08 Javascript
jQuery 自定义下拉框(DropDown)附源码下载
Jul 22 Javascript
Three.js基础学习之场景对象
Sep 27 Javascript
ionic3+Angular4实现接口请求及本地json文件读取示例
Oct 11 Javascript
用Axios Element实现全局的请求loading的方法
Mar 15 Javascript
详解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
配置Apache2.2+PHP5+CakePHP1.2+MySQL5运行环境
2009/04/25 PHP
PHP的构造方法,析构方法和this关键字详细介绍
2013/10/22 PHP
字符串长度函数strlen和mb_strlen的区别示例介绍
2014/09/09 PHP
浅谈PHP中的
2016/04/23 PHP
PHP的mysqli_sqlstate()函数讲解
2019/01/23 PHP
Laravel 解决composer相关操作提示php相关异常的问题
2019/10/23 PHP
php使用gearman进行任务分发操作实例详解
2020/02/26 PHP
写的htc的数据表格
2007/01/20 Javascript
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
Javascript创建自定义对象 创建Object实例添加属性和方法
2012/06/04 Javascript
jquery文本框中的事件应用以输入邮箱为例
2014/05/06 Javascript
NodeJS学习笔记之MongoDB模块
2015/01/13 NodeJs
JS实现的表格行鼠标点击高亮效果代码
2015/11/27 Javascript
js自定义select下拉框美化特效
2016/05/12 Javascript
Javascript 事件冒泡机制详细介绍
2016/10/10 Javascript
ajax的分页查询示例(不刷新页面)
2017/01/11 Javascript
vue接入腾讯防水墙代码
2019/05/07 Javascript
layui自定义验证,用ajax查询后台是否有重复数据,form.verify的例子
2019/09/06 Javascript
JS实现滑动插件
2020/01/15 Javascript
js实现查询商品案例
2020/07/22 Javascript
python互斥锁、加锁、同步机制、异步通信知识总结
2018/02/11 Python
用python实现k近邻算法的示例代码
2018/09/06 Python
在Python中获取两数相除的商和余数方法
2018/11/10 Python
最新pycharm安装教程
2020/11/18 Python
python实现猜拳游戏项目
2020/11/30 Python
纯CSS3制作页面切换效果的实例代码
2019/05/30 HTML / CSS
Superdry极度乾燥官网:日本街头风格,纯英国制造品牌
2016/10/31 全球购物
Ticketmaster德国票务网站:购买音乐会和体育等门票
2016/11/14 全球购物
如何判断计算机可能已经中马
2013/03/22 面试题
《落花生》教学反思
2014/02/25 职场文书
关于读书的演讲稿
2014/05/07 职场文书
人力资源职位说明书
2014/07/29 职场文书
OpenCV-Python实现怀旧滤镜与连环画滤镜
2021/06/09 Python
彩虹社八名人气艺人全新周边限时推出,性转女装男装一次拥有!
2022/04/01 日漫
SQL Server 忘记密码以及重新添加新账号
2022/04/26 SQL Server
基于Android10渲染Surface的创建过程
2022/08/14 Java/Android