函数式编程与React高阶组件
相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数。这是一个高阶函数,它可以接收函数可以当参数,也可以当返回值,这就是函数式编程。像柯里化、装饰器模式、高阶组件,都是相通的,一个道理。
本文重点是React高阶组件,要理解高阶组件,不得不说函数式编程。
1. 函数式编程
函数式编程是一种编程模式,在这种编程模式种最常用函数和表达式,函数式编程把函数作为一等公民,强调从函数的角度考虑问题,函数式编程倾向用一系列嵌套的函数来解决问题。
简单写个例子
function OCaml () {
console.log('I\'m FP language OCaml')
}
function clojure() {
console.log('I\'m FP language clojure')
}
现在想在每条console语句前后各加一条console语句,如果在每个函数都加上console语句,会产生不必要的耦合,所以高阶函数就派上了用场。
function FuncWrapper(func) {
return function () {
console.log('before')
func()
console.log('after')
}
}
var OCaml = FuncWrapper(OCaml)
var clojure = FuncWrapper(clojure)
我们写了一个函数FuncWrapper,该函数接一个函数作为参数,将参数函数装饰了一层,返回出去,减少了代码耦合。在设计模式中称这种模式为装饰器或装饰者模式。
当然函数式编程的好处不止这一条,有些人吹捧OCaml,clojure, scala等FP语言特性比如:纯函数无副作用、不变的数据、流计算模式、尾递归、柯里化等等。
在React中,高阶组件HOC就相当于这么一个FuncWrapper,传入一个组件,返回被包装或者被处理的另一个组件。
2. 高阶组件
上边已经简单说过了什么是高阶组件,其实本质上是一个类工厂。先举个例在再说
第一个组件
import React from 'react'
export default class OCaml extends React.Component {
constructor (props) {
super(props)
this.changeHandle = this.changeHandle.bind(this)
}
changeHandle (value) {
console.log(value)
}
render () {
return (
<div>
<h2>I'm OCaml</h2>
<input type="text" onchange={value => this.changeHandle(value)}/>
</div>
)
}
}
第二个组件
import React from 'react'
export default class Clojure extends React.Component {
constructor (props) {
super(props)
this.changeHandle = this.changeHandle.bind(this)
}
changeHandle (value) {
console.log(value)
}
render () {
return (
<div>
<h2>I'm Clojure</h2>
<input type="text" onchange={value => this.changeHandle(value)}/>
</div>
)
}
}
有两个不相同的组件,但是有部分功能重合,就是那个changeHandle函数,理解了高阶函数,再解决这类问题就不难了吧?不还是一样吗?
import React from 'react'
export default function CompWrapper (Component) {
return class WarpComponent extends React.Component {
constructor (props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
handleChange (value) {
console.log(value)
}
render () {
return <Component handleChange={this.handleChange} {...this.props}></Component>
}
}
}
OCaml = CompWrapper(OCaml)
Clojure = CompWrapper(Clojure)
这是一个最简单的高阶组件。注意,再高阶组件的返回包装好的组件的时候,我们将高阶组件的props展开并传入包装好的组件中,这是确保给高阶组件的props也能给到被包装的组件上。
高阶组件的通途很多,可以用来,代码复用,逻辑抽象,抽离底层代码,渲染劫持,更改state、更改props等等。
我们主要说一下两种功能的React高阶组件:属性代理、反向继承。
3. 属性代理(props proxy)
很好说了,上面已经提到过了,再来一遍,高阶组件将它收到的props传递给被包装的组件,所叫属性代理
export default function CompWrapper (Component) {
return class WarpComponent extends React.Component {
render () {
return <Component {...this.props}></Component>
}
}
}
属性代理主要用来处理以下问题
- 更改props
- 抽取state
- 通过refs获取组件实例
- 将组件与其他原生DOM包装到一起
更改props
例子是增加props的,其他的类似,都是在在高阶组件内部加以处理。
import React from 'react'
export default function CompWrapper (Component) {
return class WarpComponent extends React.Component {
say () {
console.log('我是被高阶组件包装过的组件!')
}
newProps = {
isLogin: true,
msgList: [1,2,3,4,5]
}
render () {
return <Component say={this.say} {...this.props} {...this.newProps}></Component>
}
}
}
包装好的组件可以用this.props.say调用say方法,可以用this.props.isLogin判断登陆状态等等。
抽像state
我们可以通过props和回调函数来抽象state
import React from 'react'
export function CompWrapper (Component) {
return class WarpComponent extends React.Component {
constructor (props) {
super(props)
this.state = {
inputValue: '暂时还没哟'
}
this.changeHandle = this.changeHandle.bind(this)
}
changeHandle (event) {
this.setState({
inputValue: event.target.value
})
}
render () {
return <Component {...this.props} inputValue={this.state.inputValue} changeHandle={this.changeHandle}></Component>
}
}
}
这个高阶组件将一切数据都绑定到了自己的身上,只需要出触发被包装组件的特定事件,就将改变自己的state,再将自己的state通过props传递给被包装组件。
@CompWrapper
export class InputComp extends React.Component {
render () {
return (
<div>
<h2>{this.props.inputValue}</h2>
<input type="text" onChange={this.props.changeHandle}/>
</div>
)
}
}
这里的input就成了完全受控的组件。注意:在定义组件的语句上边写上@CompWrapper是和InputComp = CompWrapper(InputComp)
作用是一样的。@操作符是ES7的decorator,也就是装饰器。
通过 refs 获取组件实例
从你的 render 方法中返回你的 UI 结构后,你会发现你想要“伸手”调用从 render 返回的组件实例的方法,我们可以通过ref获取组件的实例,但是想让ref生效,必须先经过一次正常的渲染来使ref得到计算,怎么先让组件经过一次正常的渲染呢?高阶组件又来了,明白了吗?高阶组件的render返回了被包装的组件,然后我们就可以通过ref获取这个组件的实例了。
import React from 'react'
export function CompWrapper (Component) {
return class WarpComponent extends React.Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.say()
}
render () {
const props = Object.assign({}, this.props, {ref: this.proc.bind(this)})
return <Component {...props}></Component>
}
}
}
@CompWrapper
export class InputComp extends React.Component {
say () {
console.log('I\'m InputComp')
}
render () {
return (
<button onClick={()=>{console.log(this.props)}}>点击</button>
)
}
}
当被包装的组件被渲染后,就可以执行自己实例的方法了,因为计算ref这件事已经由高阶组件做完了。
将组件与其他原生DOM包装到一起
这个很好理解,如果想把布局什么的和组件结合到一起,使用高阶组件是一个办法。
import React from 'react'
export function CompWrapper (Component) {
return class WarpComponent extends React.Component {
render () {
return (
<div style={{marginTop: 100}}>
<Component {...this.props}/>
</div>
)
}
}
}
4. 反向继承
为什么叫反向继承,是高阶组件继承被包装组件,按照我们想的被包装组件继承高阶组件。
import React from 'react'
export function CompWrapper (Component) {
return class WarpComponent extends Component {
render () {
return super.render()
}
}
}
反向代理主要用来做渲染劫持
渲染劫持
所谓的渲染劫持,就是最后组件所渲染出来的东西或者我们叫React Element完全由高阶组件来决定,通过所以我们可以对任意一个React Element的props进行操作;我们也可以操作React Element的Child。
import React from 'react'
export function CompWrapper (Component) {
return class WarpComponent extends Component {
render () {
const reactElm = super.render()
let newProps = {}
if (reactElm.type === 'input') {
newProps = {value: '这是一个input'}
}
const props = Object.assign({}, reactElm.props, newProps)
const newReactElm = React.cloneElement(reactElm, props, reactElm.props.child)
return newReactElm
}
}
}
这个例子,判断组件的顶层元素是否为一个input,如果是的话,通过cloneElement这个方法来克隆出一个一样的组件,并将新的props传入,这样input就有值了。
用过React-Redux的人可能会有印象,使用connect可以将react和redux关联起来,这里的connect就是一个高阶组件,想到这,就很容易想出connect高阶组件是怎么实现了,我会在写一篇随笔,自己实现一个redux、connect、midlleware还有thunk。
函数式编程与React高阶组件的更多相关文章
- 聊聊React高阶组件(Higher-Order Components)
使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...
- react高阶组件的理解
[高阶组件和函数式编程] function hello() { console.log('hello jason'); } function WrapperHello(fn) { return fun ...
- 当初要是看了这篇,React高阶组件早会了
当初要是看了这篇,React高阶组件早会了. 概况: 什么是高阶组件? 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说 ...
- React高阶组件学习笔记
高阶函数的基本概念: 函数可以作为参数被传递,函数可以作为函数值输出. 高阶组件基本概念: 高阶组件就说接受一个组件作为参数,并返回一个新组件的函数. 为什么需要高阶组件 多个组件都需要某个相同的功能 ...
- 利用 React 高阶组件实现一个面包屑导航
什么是 React 高阶组件 React 高阶组件就是以高阶函数的方式包裹需要修饰的 React 组件,并返回处理完成后的 React 组件.React 高阶组件在 React 生态中使用的非常频繁, ...
- react高阶组件的一些运用
今天学习了react高阶组件,刚接触react学习起来还是比较困难,和大家分享一下今天学习的知识吧,另外缺少的地方欢迎补充哈哈 高阶组件(Higher Order Components,简称:HOC) ...
- day03 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数
本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 温故知新 1. 集合 主要作用: 去重 关系测 ...
- React: 高阶组件(HOC)
一.简介 如我们所知,JavaScript有高阶函数这么一个概念,高阶函数本身是一个函数,它会接收或者返回一个函数,进而对该函数进行操作.其实,在React中同样地有高阶组件这么一个东西,称为HOC, ...
- React——高阶组件
1.在React中higher-order component (HOC)是一种重用组件逻辑的高级技术.HOC不是React API中的一部分.HOC是一个函数,该函数接收一个组件并且返回一个新组件. ...
随机推荐
- 错误检查roswtf
准备 在你开始本教程之前请确保roscore没在运行. 安装检查 roswtf 可以检查你的ROS系统并尝试发现问题,我们来试看: $ roscd $ roswtf 你应该会看到(各种详细的输出信息) ...
- jenkins持续集成python cases
1. 官网2.7jenkins.war下载 http://mirrors.jenkins.io/war-stable/2.73.2/jenkins.war jdk-x86 linux 32bit适用 ...
- OpenJudge 4001:抓住那头牛
题目链接 题解: 这个题可以用广搜来解决,从农夫到牛的走法每次都有三种选择,定义一个队列,把农夫的节点加进队列,然后以这三种走法找牛,队列先进先出,按顺序直到找到牛的位置. 代码: #include& ...
- mysql/mariadb学习过程中出现的问题与解决
mysql> insert into student values(,,'CS'); ERROR (): Duplicate entry ' for key 'PRIMARY'(duplecat ...
- jQuery----获取兄弟元素的方法
① $(this).next(): 获取的是当前元素的下一个兄弟元素 ②$(this).nextAll(); 获取的是当前元素的后面的所有的兄弟元素 ③$(this).pre ...
- 利用Dropbox中转自己的C2
利用Dropbox中转自己的C2 0x00 前言 本来的目的呢,是利用dropbox中转自己的c2达到免杀的效果,然后可能是看了文章太久没抓住机会复现,到最后发现已经失效了,会被360拦截,所以好像也 ...
- Java基础——常用类之日期时间类
如果有机会,请尝试Java8中全新的时间日期API!(参见Java8新特性随笔) 如果还是使用Java7及之前的版本,那么你可以尝试一些工具类(参考使用工具类相关的Hutool-DateUtil) 如 ...
- 20155238 2016-2017-2 《Java程序设计》第四周学习总结
教材学习内容总结 继承 extends public class SwordsMan extends Role 检查语法逻辑,从=右边向左边读.编译程序就是语法检查器. 重新定义行为 public v ...
- jQuery学习-事件绑定
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 【转载】MSXML应用总结 开发篇(上)
原文:http://blog.sina.com.cn/s/blog_48f93b530100ejv9.html 本篇是接前文“MSXML应用总结 概念篇”写的,主要总结一下MSXML DOM接口的应用 ...