查看原文
其他

【第1428期】React v16.7 "Hooks" - What to Expect

cyan 前端早读课 2019-06-05

前言

到周末了,React界昨天又有点动静了。今日早读文章由Facebook@cyan授权分享。

正文从这开始~~

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

关于本文
作者:@cyan
原文:https://zhuanlan.zhihu.com/p/47684983

最后,为你推荐


【第1417期】浅析 React / Vue 跨端渲染原理与实现


【第1414期】缓存 React 事件监听器来提高性能


【活动】第二届Vue.js开发者大会,11月24号杭州见!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存