高阶组件

本质

本质是函数,将组件作为接收参数,返回一个新的组件。HOC本身不是React API,是一种基于React组合的特而形成的设计模式。

解决的问题(作用)

  • 一句话概括:功能的复用,减少代码冗余
  • 进一步解释:在实际情况中,多个组件可能会做某些相同的事情,有着相同的功能,存在大量的代码冗余。我们可以将这部分功能拆分出来,每个组件尽量只保留自己独有的作用,通过HOC生成我们最终需要的组件。

实现方法:

无论哪种方法,都是在HOC函数内定义新的组件,在新的组件内做一些公共的功能和事情

  1. 属性代理
  2. 反向继承

属性代理

这是最常规的写法,原理等同于ES7装饰器、Python装饰器。函数传入的参数,除了原组件,还可以定义其他的参数,通过这些参数来区别每个实际组件。比如,公共的功能是获取数据。获取数据这件事情是相同的,但获取的内容不同。如何决定最后生成的组件获取各自指定的内容呢?通过函数传参。

// 示例用localstorage代替如网络请求等的异步操作
localStorage.setItem("comment","asuiklfhs");
localStorage.setItem("read","123"); class Comment extends React.Component { render() {
return (
<div>
{this.props.data}
</div>
)
}
} class Read extends React.Component { render() {
return (
<div>
{this.props.data}
</div>
)
}
} const HOCTest = (key) => {
return (WrappedComponent) => {
return class NewComponent extends React.Component{ constructor(props) {
super(props);
this.state = {
data: ''
};
} componentDidMount() {
const data = localStorage.getItem(key);
this.setState({
data
});
} render() {
console.log(this.myRef);
return (
<div ref={(e)=>{this.myRef = e;}}>
<WrappedComponent {...this.props} data={this.state.data} />
</div>
);
}
}
}
}; const CommentNew = HOCTest("comment")(Comment); // HOC生成新组件
const ReadNew = HOCTest("read")(Read); class Root extends React.Component {
render() {
return (
<div className="App">
Hello World
<CommentNew/>
<ReadNew/>
</div>
);
}
}

在这里,React第三方的组件库通常使用 函数柯里化 的写法。对于使用者来说,改变了调用函数时的传参方式,更加容易理解。即:原本调用函数wrapper(Component, params1, params2)  柯里化后调用wrapper(params1,params2)(Component)

属性代理常见的作用:

  1. 操作props
  2. 通过Refs访问组件实例
  3. 提取state
  4. 组合更多的html元素

反向继承

顾名思义,就是将返回的组件继承了原组件。它允许生成的组件通过this获取原组件,意味着可以获取到state,props,生命周期钩子,以及render

localStorage.setItem("comment","asuiklfhs");
localStorage.setItem("read","123"); class Comment extends React.Component {
constructor(props){
super(props);
this.state = {id:"comment"}
} componentDidMount() {
console.log("Comment DidMount");
} render() {
return (
<div>
{this.props.data}
</div>
)
}
} class Read extends React.Component {
constructor(props){
super(props);
this.state = {id:"read"}
} render() {
return (
<div>
{this.props.data}
</div>
)
}
} const HOCTest = (key) => {
return (WrappedComponent) => {
return class NewComponent extends WrappedComponent{ componentDidMount() {
console.log("HOC DidMount");
const data = localStorage.getItem(key);
this.setState({
...this.state,
data
});
} render() {
return (
<WrappedComponent data={this.state.data}/>
);
}
}
}
}; const CommentNew = HOCTest("comment")(Comment);
const ReadNew = HOCTest("read")(Read); class Root extends React.Component { render() {
return (
<div className="App">
Hello World
<CommentNew/>
<ReadNew/>
</div>
);
}
}

作用:

  1. 渲染劫持。由于新组件可以控制原组件的render方法,可以做各种控制渲染的操作。
  2. 操作state

注意点:

  1. 不要在函数内修改原组件
  2. 使用反向继承方式时,会丢失原本的显示名
  3. 不要在render函数中使用HOC

高阶组件的缺点:

  1. 难以溯源。如果原始组件A通过好几个HOC的构造,最终生成了组件B,不知道哪个属性来自于哪个HOC,需要翻看每个HOC才知道各自做了什么事情,使用了什么属性。
  2. props属性名的冲突。某个属性可能被多个HOC重复使用。
  3. 静态构建。新的组件是在页面构建之前生成,先有组件,后生成页面。

Render Props

作用

  1. 功能的复用,与HOC类似。
  2. 组件间数据的单向传递。

什么是Render Props?

是一个用于告知组件要渲染什么内容的函数属性。该函数返回一个组件,是渲染出来的内容。

class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<p>位置:x:{ mouse.x } y: { mouse.y }</p>
);
}
} 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>移动鼠标!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}

通过以上Demo可以看到,Mouse组件通过render属性(属性名也可以是别的名字),指定了渲染哪个子组件,并且子组件可以接收参数值,进而实现内部逻辑。

再进行分析,发现Mouse组件提供可变数据源,是一个基础数据的提供者,最关键的代码是:

{this.props.render(this.state)}

通过render属性,将数据传递给另外一个组件。至于这个数据拿来干什么,怎么去渲染,就不是它管的事情了。

因此,整个页面很多地方可能需要用到鼠标坐标数据,以上的例子就可以实现功能的复用。

相对高阶组件的优点:

  1. 不用担心props的命名冲突的问题
  2. 可以溯源,子组件的props一定来自父组件。
  3. 是动态构建的,页面在渲染后,可以动态地决定渲染哪个组件。
  4. 所有能用HOC完成的事情,Render Props都可以做,且更加灵活。
  5. 除了功能复用,还可以用作两个组件的单向数据传递。

React高阶组件 和 Render Props的更多相关文章

  1. 聊聊React高阶组件(Higher-Order Components)

    使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...

  2. 当初要是看了这篇,React高阶组件早会了

    当初要是看了这篇,React高阶组件早会了. 概况: 什么是高阶组件? 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说 ...

  3. react高阶组件的理解

    [高阶组件和函数式编程] function hello() { console.log('hello jason'); } function WrapperHello(fn) { return fun ...

  4. 函数式编程与React高阶组件

    相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数.这是一个高阶函数,它可以接收函数可以当参数,也 ...

  5. 利用 React 高阶组件实现一个面包屑导航

    什么是 React 高阶组件 React 高阶组件就是以高阶函数的方式包裹需要修饰的 React 组件,并返回处理完成后的 React 组件.React 高阶组件在 React 生态中使用的非常频繁, ...

  6. react高阶组件的一些运用

    今天学习了react高阶组件,刚接触react学习起来还是比较困难,和大家分享一下今天学习的知识吧,另外缺少的地方欢迎补充哈哈 高阶组件(Higher Order Components,简称:HOC) ...

  7. React高阶组件学习笔记

    高阶函数的基本概念: 函数可以作为参数被传递,函数可以作为函数值输出. 高阶组件基本概念: 高阶组件就说接受一个组件作为参数,并返回一个新组件的函数. 为什么需要高阶组件 多个组件都需要某个相同的功能 ...

  8. React——高阶组件

    1.在React中higher-order component (HOC)是一种重用组件逻辑的高级技术.HOC不是React API中的一部分.HOC是一个函数,该函数接收一个组件并且返回一个新组件. ...

  9. react 高阶组件的 理解和应用

    高阶组件是什么东西 简单的理解是:一个包装了另一个基础组件的组件.(相对高阶组件来说,我习惯把被包装的组件称为基础组件) 注意:这里说的是包装,可以理解成包裹和组装: 具体的是高阶组件的两种形式吧: ...

随机推荐

  1. nginx部署为HTTP代理支持CONNECT模式

    有个软件要走http代理,想着部署nginx起来用,结果发现用不了: 而用ccproxy的话,一切正常: 抓包分析了下,是CONNECT模式的请求 从nginx的官网http://nginx.org/ ...

  2. Chapter 5 查找

    Chapter 5 查找 1-   顺序查找法 O(n) 2-   折半查找O(logn) :二分查找 要求:关键字有序 过程: 判定树:叶子结点为方框,代表不成功的结点. 3-   分块查找:索引顺 ...

  3. 前端面试题(js部分)

    一.==和===的区别 1.==   用于比较.判断两者相等,比较时可自动换数据类型 2.===  用于(严格)比较.判断两者(严格)相等,不会进行自动转换,要求进行比较的操作数必须类型一致,不一致时 ...

  4. 利用animate.css和es6制作文字向上滚动的效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel= ...

  5. php基础学习过程

    1.基础知识 a.注释: <?php // 这是单行注释 # 这也是单行注释 /* 这是多行注释块 它横跨了 多行 */ ?> b.大小写敏感: 在 PHP 中,所有用户定义的函数.类和关 ...

  6. SQL Server代码如何快速格式化,sqlserver代码

    在SQL Server中我们经常需要编写各种SQL脚本,例如存储过程和函数等,由于在编写过程中,经常会进行调整,有些关键字我们用的大写,有的我们用的小写,有的后面结束用:分割有的又没有.对于有强迫症的 ...

  7. 软件-SecureCRT:SecureCRT

    ylbtech-软件-SecureCRT:SecureCRT SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录UNIX或Linux服务器主机的软件 ...

  8. 使用alibaba的json工具将String类型转为JSONArray类型

    转化流程:先将输入流转为String类型,再使用alibaba的json转换工具,将字符串转化为json数组 SensorDevices sensorDevices = new SensorDevic ...

  9. Luogu P2051 [AHOI2009]中国象棋(dp)

    P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...

  10. Go之路一

    一.声明变量 var a int var b string var c []float32 var d func() bool var e struct{ x int } 第1行,声明一个整型类型的变 ...