Reactv16.7″Hooks”-WhattoExpect

技術小能手發表於2018-11-02

什麼是 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)。但是限於篇幅,很多功能強大的部分和一些注意事項在這篇文章裡並沒有過多講解,請大家移步官方文件學習更詳細的姿勢(牆裂推薦)。


原文釋出時間為:2018-11-02

本文作者:cyan

本文來自雲棲社群合作伙伴“前端大學”,瞭解相關資訊可以關注“前端大學”。


相關文章