在2018年React Conf大會上,React團隊講解了目前你們使用React開發過程存在的一些問題並推出了一個使人激動的概念:React Hooks,並介紹hooks如何解決這些問題。恰好我所在的團隊前端使用的是react+ts+node這套技術棧,前段時間將react版本升級到了16.8,在這個過程當中使用到了hooks的功能。在這裏寫下本身的感覺和看法。前端
本文將從如下幾部分進行總結:node
在react hooks問世以前,react能提供給組件間複用邏輯採用的是mixin,但這種方式弊端很是多,因此你們基本都是用render props(渲染屬性)和HOC(高階組件)來複用組件間的邏輯。但這兩種方式的缺點也是很是明顯的,很容易產生「wrapper hell」,即組件很容易臃腫,增長了debugger的成本。react
在稍微複雜的業務邏輯當中,生命週期是繞不過去的問題。有不少場景下在componentDidmount處理的邏輯不得不又在componentDidUpdate從新處理一次,業務被分散在各個不一樣的生命週期函數中。 編程
而Hooks的出現,從面向生命週期編程轉變爲面向業務邏輯編程 數組
雖然Hooks以前能夠編寫純函數組件,但它只能是無狀態的。很是常見的狀況是你編寫了一個純函數組件,但過一段時間你發現得加上一個狀態,這時候不得不將純函數組件改成類組件。這時候得處理this的問題,並且編譯器對class也是不友好的。bash
import { useState, useEffect } from 'react'
function Example(props) {
// 聲明一個新的狀態變量"count"
const [count, setCount] = useState(0);
useEffect(() => {
subscribe(props.number, setCount)
return () => {
unsubscribe(props.number)
}
})
return <div>{count}</div>
}
複製代碼
useState會接受一個初始值,而後會返回一個[狀態,狀態修改器]的二元組。每次從新渲染時,整個函數會從新執行,可是useState會記住上次的值。並且react是根據useState的調用順序來記得狀態歸屬的:app
const Example = () => {
const [size, setSize] = useState({ width: 100, height: 100 });
const [count, setCount] = useState(0);
}
複製代碼
每一次 Example 被渲染,都是第一次 useState 調用得到 size 和 setSize,第二次 useState 調用得到 count 和 setCount。函數
useEffect是用來處理反作用的,至關於之前的componentDidMount和componentDidUpdate。它能夠返回一個函數,用來在組件卸載前調用。因此useEffect聚合了componentDidMount,componentDidUpdate和componentWillUnmount的操做。若是props.number沒有改變,咱們是不但願在useEffect訂閱/取消訂閱裏從新執行的,爲了實現這個操做,只須要傳入一個參數便可。ui
useEffect(() => {
subscribe(props.number, setCount)
return () => {
unsubscribe(props.number)
}
}, [props.number])
複製代碼
它是一個數組,只要這個數組中的每個值都不發生變化,則useEffect不須要從新執行。this
在將react升級以後,生命週期函數遷移到函數組件能夠按照如下方式來操做:
在react hooks開發的過程當中,共享代碼會採起函數組件的形式。約定使用useXXX開頭,想重用這些代碼,在函數式組件經過調用useXXX便可。
例如咱們能夠寫這樣一個useMountLog,在組件mount的時候打印出一條日誌:
const useMountLog = (name) => {
useEffect(() => {
console.log(`${name} mounted`);
});
}
複製代碼
這樣一來,全部的函數式組件中均可以經過調用useMountLog來使用這個功能:
const Example = () => {
useMountLog('Example')
}
複製代碼
再好比能夠經過寫useWindowWidth這樣一個自定義hook來反映當前窗口的寬度
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
});
return width;
}
複製代碼
這樣就能夠在其餘函數式組件中使用:
function MyResponsiveComponent() {
const width = useWindowWidth();
return (
<p>Window width is {width}</p>
);
}
複製代碼
在上邊的例子能夠看到,react hooks大大地減小咱們的代碼量。而hooks只能在函數式組件中使用,因此能夠預測雖然如今react仍然支持類組件,但之後類組件會慢慢得消亡。
React Hooks的出現,將大大地減小react的代碼量,解決原來使用react開發遇到的一些問題,也給開發帶來了一些變化。包括:
最後,引用 Dan Abramov 在React Conf 2018 上的演講詞結束本文:
「……我曾經疑惑,React 的 Logo 爲何是一個原子?後來我想到了這個解釋。咱們知道物質由原子組成,是原子的特性決定了物質的外觀和行爲。就像 React,你能夠把用戶視圖拆成獨立的組件,再像原子同樣自由組合起來,是組件的特性決定了用戶視圖的行爲。科學家們曾一度認爲原子是不可分割的最小單位,直到發現了電子,一種原子內部更小的粒子。事實上,是電子的特徵影響了原子的性質。我認爲 hooks 就比如電子,與其說它是一個新特性,不如說是已知的 React 特性(state,context,生命週期)的更直接的展示形式,而這四年來咱們卻一直對它視而不見。
若是盯着 React 的 logo 看的話,你會發現 hooks 其實一直都在。」