微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

React v16.7 "Hooks" - What

2018-10-28 20:00 前端大全


(点击上方公众号,可快速关注)


作者:cyan

https://zhuanlan.zhihu.com/p/47684983


Hooks 目前已经在 v16.7.0 alpha 版本,如果想了解更多的关于这个功能的介绍和讨论,可以移步文章底部的 Proposal discussion 和文档链接。

什么是 Hooks?

Hooks 是一个 React 函数组件内一类特殊的函数(通常以 “use” 开头,比如 “useState”),使开发者能够在 function component 里依旧使用 state 和 life-cycles,以及使用 custom hook 复用业务逻辑。

动机

在 React 里,function component 就是一个 pure render component,没有 state 和 component life-cycle。如果需要这两个中的任意一个,就需要变成 class component。在既有的 React API 下,这个模式有如下一些缺点:

组件间交流的耦合度很高,组件树臃肿

在既有的模式下,React 的组件间通信无非是两种,一种是单项数据流,另一种是通过 redux 之类的 global store 来实现全局状态和各组件间的解耦。当有些状态不适合放在 global store 的情况下,组件间逻辑的复用和沟通就变得十分困难(必须一层一层往下传)。这一点在 Higher order component (高阶组件) 和 render props 中尤其常见。我们为了复用一些逻辑,单独创造了很多 HOC(高阶组件) 来向下传递状态。这导致的问题就是当我们的应用规模变得越来越大的时候,一些无关 UI 的 wrapper 组件越来越多,React 组件树变得越来越臃肿(在 devtool 中可以甚至看到数十层 wrapper)。某些业务场景下,一个 Tooltip component 里面都嵌套了三四层额外的组件,使开发和调试的效率变得很低。

在新的 React hook 中,我们可以创建 custom hook,在其中复用一些逻辑,这些逻辑不再出现在组件树中,而是成为一个单独的,独立的逻辑单元,但是他们仍然响应 React 在渲染之间的变化。

JavaScript 的 class 产生的诸多疑惑

这一点是相对于 JavaScript 来说的。还记得刚入门 JavaScript 的时候,需要跨越的一个重要难关就是 ”this” 指向,以及原型链,继承这些问题。即使我们真正觉得明白了其中的原理,在日常的开发中也难免因为疏忽而踩坑,这一系列的问题导致新手相对比较难上手 React。举个简单的例子,React 组件内的 event listener 之前需要手动 bind this 的问题,这个问题就很难对一个 JavaScript 入门的新手解释明白。

而这一系列的问题,将在 Hook 中被极大地解决。如果没有 class,没有了 this,可能上述的种种问题都不再是问题了。

Write Hooks

说了这么多,Hooks API 是什么样呢?首先需要声明的是,Hooks 是向后兼容的,class component 不会被移除。作为开发者,可以慢慢迁移到这个新的 API。

Hooks 主要分为三种:

  • State hooks (在 function component 中使用 state)

  • Effect hooks (在 function component 中使用生命周期和 side effect)

  • Custom hooks (自定义 hooks 用来复用组件逻辑,解决了上述的第一个动机中阐述的问题,这一部分就不在此多费篇幅介绍了,请大家移步文档)。

State hooks
import { useState } from 'react';
function Example() {
 
// Declare a new state variable, which we'll call "count"
 
const [count, setCount] = useState(0);
 
return (
   
<div>
     
<p>You clicked {count} times</p>
     
<button onClick={() => setCount(count + 1)}>
       
Click me
     
</button>
   
</div>
 
);
}

之前讲过 hook 本质是一个特殊的函数(通常以 “use” 开头)。在这里,”useState” 就是一个 hook,通过它我们能够嵌入组件内部的 state。这个函数返回一个 pair,第一个值是当前对应这个 hook 的 state 值,第二个是怎样更新这个值。

我们可以从中感觉到,这两个返回值分别对应的以前的用法是:

  • this.state

  • this.setState


除此之外,我们还可以在一个函数组件中使用多个 useState:


function ExampleWithManyStates() {
 
// Declare multiple state variables!
 
const [age, setAge] = useState(42);
 
const [fruit, setFruit] = useState('banana');
 
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
 
// ...
}

这给我们的一个非常大的好处就是我们能够避免组件的 state 结构过于臃肿(因为之前每个 component class 只能有一个 state),能够独立处理每个 state。另一个好处就是这种写法非常直观,一眼就可以看出和这个 state 相关的两个变量,比如 [age, setAge]。

Effect hooks
import { useState, useEffect } from 'react';
function Example() {
 
const [count, setCount] = useState(0);
 
// Similar to componentDidMount and componentDidUpdate:
 useEffect
(() => {
   
// Update the document title using the browser API
   document
.title = `You clicked ${count} times`;
 
});
 
return (
   
<div>
     
<p>You clicked {count} times</p>
     
<button onClick={() => setCount(count + 1)}>
       
Click me
     
</button>
   
</div>
 
);
}

我们还需要解决一个问题,那就是怎样在 function component 里使用 life-cycles,生命周期函数。在这里,所有的 life-cycles,比如 componentDidMount, componentDidUpdate, shouldUpdate, 等等都集合成一个 Hook,叫做 useEffect。这个函数类似 redux 中的 subscribe,每当 React 因为 state 或是 props 而重新 render 的之后,就会触发 useEffect 里的这个 callback listener(在第一次 render 和每次 update 后触发)。

为什么叫 useEffect 呢?因为我们通常在生命周期内做的操作很多都会产生一些 side-effect(副作用)的操作,比如更新 DOM,fetch 数据,等等。

Other Built-in Hooks

除了 useState, useEffect 还有另外一些 React 自带的 hooks。比如:

  • useContext


替代了 <Context.Consumer> 使用 render props 的写法,使组件树更加简洁。


  • useReducer


相当于组件自带的 redux reducer,负责接收 dispatch 分发的 action 并更新 state。


详细用法请看文档。

总结

读到这里,你可能理解了为什么这个新的 API 被叫做 “Hooks” 了。”Hooks” 本意是”钩子“的意思。在 React 里,hooks 就是一系列特殊的函数,使函数组件 (functional component) 内部能够”钩住“ React 内部的 state 和 life-cycles。

这个向后兼容的 API 在解决了一些既有问题的情况下,不仅使我们能够更好地使用 state 和 life-cycles,真正功能强大的地方是使我们能够更轻松地复用组件逻辑(custom hooks)。但是限于篇幅,很多功能强大的部分和一些注意事项在这篇文章里并没有过多讲解,请大家移步官方文档学习更详细的姿势(墙裂推荐)。

Discussion RFC:
https://github.com/reactjs/rfcs/pull/68

Document and Overview:
https://reactjs.org/docs/hooks-intro.html


【关于投稿】


如果大家有原创好文投稿,请直接给公号发送留言。


① 留言格式:
【投稿】+《 文章标题》+ 文章链接

② 示例:
【投稿】《不要自称是程序员,我十多年的 IT 职场总结》:http://blog.jobbole.com/94148/

③ 最后请附上您的个人简介哈~



觉得本文对你有帮助?请分享给更多人

关注「前端大全」,提升前端技能

 
前端大全 更多文章 微前端 - 将微服务理念延伸到前端开发中 WebAssembly 的未来:将逐渐解锁整个“技能树” 神奇的 CSS3 混合模式 前端性能优化原理与实践 React 新 Context API 在前端状态管理的实践
猜您喜欢 python生成二维码 顶级开源再添新军 阿里巴巴正式开源全球化OpenMessaging和ApsaraCache项目 分享:数据驱动产品运营的增长之道 谷歌机器学习进展:让电脑一句话描述图片内容 Vue 2.0 构建单页应用最佳实战