React hooks更深入的理解

2019 / 09 / 16

hooks的使用规则

hooks只能在function component的最外层使用。这里有两点

1. 只能在React的function Component中用。

2. 只能在最外层用,不能封装起来,不能在条件语句或者循环语句里用。

当然记住这个不难,想要限制开发者不要写错的话,可以用官方推出的插件,eslint-plugin-react-hooks,官方的呢肯定没什么问题,但是为什么呢,这种不讲道理的限制很显然是不能让开发者心服口服的。

官网稍微说了一下原因,我们是按照顺序来找state的,假如某个hook不执行,那么后续的hook都会出bug。因为顺序不对了,这个很奇怪,说实话代码敢这么设计的貌似也只有React了,虽然设计出来之后大家都赞不绝口,也没什么说闲话的,useState用数组解构的方式也可以理解,因为这个对于javascript来说已经是最好的方法了,但是讲真,API这么设计真的好么。

这个问题我们存疑,关乎到hooks的实现原理,然后继续看看另外一个东西,这就是自定义hooks。

设计hooks的动机

为了说明自定义hooks解决的问题,不得不插一句设计hooks的动机。

无论是jsx,高阶函数,还是插槽,或者是Refs和Context上下文,React总是在日以继日的造一些新的概念去解决复杂的问题,尽管总的来说,React解决的还是非常非常的优秀的,但是造轮子总是会迎来新的轮子的问题。毕竟人类再怎么的心灵手巧以抵不过大自然的鬼斧神工。所以React造的轮子也并不是考虑的非常周到,总会有些让人诟病的东西。

比如说写组件要用class。组件化也是一种面向对象,尤其是在React中,每次调用组件都是在进行一次实例化,所以看起来挺面向对象。但仔细想一下,我们并不会写一些RoundButton extends Button之类的代码,而渲染界面其实更像是在通过renderHeader,renderFooter之类方法来描述界面。

但是React为什么要用class呢,明明就不是很面向对象的。究其原因,首先需要看看它的实现,使用组件需要实例化,定义组件的时候需要按照约定去描述它的生命周期和通过执行 this.setState来改变状态,这个时候就能拿到setState的this,也就是被更新的组件,然后推到dirtyComponent中,最后再进行diff更新组件,重新经过生命周期。不得不说用了上下文解决这个问题就会简单很多。而且也很符合组件化的思想,说不定哪天就各种互相extends了。

但是发展了五年,第一个五年规划过去了。React其实走的风格蛮函数式的,而且this的上下文的坑和组件使用的各种角度来看,貌似轻量化,函数化,属性和状态导向型的组件更加会被社会所认可,于是乎,React做出了hooks,配合函数式的组件化编程可以解决非常非常多的实际问题。

hooks承载了解决过于一直为人诟病的React的问题的使命,官方也给出了一个他们设计hooks的动机。可以参考 官方文档

hooks解决了的问题有

1. 组件之间很难复用状态

2. 复杂组件难以理解

3. class语法

其中第二个是在上一篇文章中讲的,通过把问题专注在state和props的变化来解决。第三个是hooks天然就能解决的。第一个问题的解决就是通过自定义组件。

自定义hooks和高阶组件

尽管使用高阶组件可以很好的解决一些复用逻辑的问题,但是对于状态,副作用和生命周期而言高阶组件解决起来也经常显得非常吃力,React对于这个问题给出了一个更好的方式就是自定义hooks,每个组件通过公用副作用和状态,来实现业务逻辑的复用。当然高阶组件可以解决某些问题还是更加方便的,尤其是增强组件方面。

可以理解为高阶组件是一种enhancer(增强器),而hooks是一种能力插槽。

hooks的使用也很简单,可以单纯的理解为把公共的useState或者useEffect包了一层,然后不同的组件拿去公用就行了。

通过明白自定义hooks的使用,可以更清晰的看到hooks的一个本质。

把组件的jsx和逻辑更加彻底的分离开。

而通过使用hooks的规则和自定义组件综合可以发现,hooks是通过顺序执行来管理状态和副作用的,所以它的原理可能更加类似于堆栈调用,只要破坏了顺序就无法正常执行了,而自定义hooks也只是把代码块挪来挪去,并不会改变任何调用方式和状态,状态只存在于组件的内存中,并不是属于某个hooks的,所以公用状态的hooks只是公用了设置状态的逻辑,并不是数据。

嗨,请先 登录

加载中...
(๑>ω<๑) 又是元气满满的一天哟