前言
自從 2019.2.6 React 16.8 發布以來,新特性 Hooks 徹底顛覆了以往的開發模式,我最早使用 Hooks 是在兩年前,現在我們團隊也在項目中大量使用該特性,并沉淀了一套 Hooks 底盤。
今天的分享主題叫《React Hooks 從相識到相愛》,整個分享我會以一條故事線的形式展開,初次相識 -> 萌生心動 -> 主動約會 -> 大膽表白。我會帶大家從完全不知道什么是 Hooks,到喜歡上她,并能夠在實際工作中用起來。
大家應該都寫過函數組件,函數組件是沒有狀態的,如下是一個計數組件的示例,我想這個需求大家應該10s鐘就能夠寫出來~
import React from "react";
import { View, Text, Button } from "react-native";
function CountComponent(props) {
return (
<View>
<Text>You clicked {props.count} times</Text>
<Button onClick={() => props.addCount()}>Click me</Button>
</View>
);
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<CountComponent
count={this.state.count}
addCount={() => {
this.setState(this.state.count + 1);
}}
/>
);
}
}
我們封裝了一個 CountComponent
組件,狀態由 App class 組件控制,是一個完全受控組件。
細心的同事應該發現了,上面的代碼有點冗余是吧,本質上 count
狀態是可以直接封裝在 CountComponent
里面的,不用放在父組件里面傳進去。
但是在 React 16.8 之前,React 只給類組件提供了管理狀態的功能,函數組件無法獨立完成狀態管理的工作。
而這個現狀隨著 React 16.8 的 Hooks 的到來也被打破了。
React Hooks 可以讓你在不編寫 Class 的情況下使用 state 以及生命周期等 React 特性。
Hook 這個單詞的意思是"鉤子"。它的作用是可以讓你在函數組件里“鉤入” React state 及生命周期等特性的函數。 React Hooks 其實就是一系列鉤子函數。
類組件通過繼承 React.Component 獲得 state 以及生命周期等功能來連接到 React 狀態機里面;而 React Hooks 則是通過一系列鉤子達到同樣的目的。
用一張圖讓大家對 Hooks 有更清晰的認識:
通過 Hook 把上面的計數組件狀態遷移到 CountComponent
組件中:
import React, { useState } from "react";
import { View, Text, Button } from "react-native";
function CountComponent() {
const [count, setCount] = useState(0); // 非常陌生的代碼
return (
<View>
<Text>You clicked {count} times</Text>
<Button onPress={() => setCount(count + 1)}>Click me</Button>
</View>
);
}
export default class App extends React.Component {
render() {
return <CountComponent />;
}
}
useState
就是我們即將要學習的一個 Hook,我們先不管這個玩意是干什么用的,從表面來看我們可以簡單的對這個 Hook 得出幾個結論:
-
useState
返回一個數組,這個數組里面有兩個元素,通過 ES6 的數組解構賦值語法分別賦給了count
和setCount
-
count
會在CountComponent
重新渲染的時候獲取最新的狀態,類似于 Class 中的this.state
;setCount
用于更新count
觸發重新渲染,類似于 Class 中的的this.setState
關于 ES6 數組解構語法,目的是為了讓寫法更簡潔。除了數組可以解構,對象也是可以解構的,這里就不展開了,有興趣可以去查看下 ECMAScript 6 的文檔。
讓我們對 hooks 的第一印象做個總結
- Hooks 是 React 16.8 的新增特性,它可以讓函數組件擁有 state 以及生命周期等 React 特性。
- Hooks 其實是一系列”鉤子“函數
- 代碼更少、寫法更簡單(一個簡單的函數、不用繼承、寫構造函數等)
1、更符合”函數式“思想
React 組件一直更像是函數,而 Hook 則擁抱了函數
如果大家看過 React 的設計思想,就會發現 React 強調最多的就是函數,傳入一個狀態,得到一個UI。
而 React Hooks 就是一系列函數,所以更符合 React 的設計思想,也是 React 大力推行 Hooks 的原因之一。
2、類組件冗余的繼承和構造函數
每一個 Class 組件都要繼承 React.Component
,以此獲得 state、生命周期等 React 能力:
class CustomComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
a: 0
}
}
render() {
return (
<View>
<Text>{this.state.a}</Text>
</View>
)
}
}
大家寫習慣了可能覺得沒啥了,那我們來對比下 hooks 的代碼:
const CustomComponent = function() {
const [a, setA] = useState(0)
return (
<View>
<Text>{a}</Text>
</View>
)
}
這里用 hooks 實現了功能一樣的組件,大家可以先不用關注實現,可以看到 hooks 的寫法明顯簡潔很多,沒有繼承、沒有構造函數、沒有 render 重寫等等。其實函數組件整體的代碼量都比類組件要少。
我這里把 類組件 和 函數組件 壓縮后的代碼進行了對比:
類組件做了語法糖的包裝,原型擴展、super、this 的處理等等,就拿剛才那個組件來說,函數組件的整體代碼量大概只有類組件的一半,減少了50%。
當然復雜組件達不到這個降幅,但是不可否認是,函數組件對包大小的優化是有明顯收益的,所以如果你想要減少包大小,那么現在就開始使用 Hooks 吧。
3、類組件混亂的生命周期函數
我們知道類組件有一大堆生命周期方法,這幅圖展示是 React 16 之前的生命周期圖,大家應該都比較熟悉:
有人可能會問,這里面不是有些生命周期函數被廢棄了嘛?是的,在 React 16 的時候 ,為了適配 Fiber 架構,廢棄了幾個render期的生命周期函數。
所以 15 和 16 的生命周期流程是不一樣的!
上面用黃色標記的就是 React 16 廢棄的生命周期函數,為了避免開發者再次使用,React 直接在這些生命周期函數前加上了 UNSAFE_ 前綴,意指不安全的。
什么是不安全的?為什么要廢棄?
具體為什么是不安全的,大家可以去看 Fiber 架構說明,這里就不展開。
然后你以為這就結束了?React 在廢棄這三個生命周期函數的同時,又新增了兩個生命周期函數.... 如下:
新增的兩個函數,一個是靜態函數 getDerivedStateFormProps
,一個 getSnapshotBeforeUpdate
。這兩又是干啥的?
看到這里是不是已經懵了,這么多生命周期函數該怎么用? 感覺腦殼都疼了。
反觀 Hooks,React Hooks 弱化了生命周期函數的復雜概念,將 React 各個渲染節點注入到鉤子里面去了,大大簡化了上手難度。
我們只要掌握了 useState
、useEffect
基本就可以打天下了。
4、this 指向問題
this
指向問題是 JS 歷來的坑點,ES5 判定 this
指向可以通過查看 new
調用、顯示綁定(call
、bind
、apply
)、默認綁定 等等因素決策,但 ES6 之后有了箭頭函數和類,this
綁定的規則也有所改變。
當然 this
問題并不是只在 類組件中存在,但是 類組件會蒙蔽開發者,讓他們以為自己拿到的 this
是你認為對的 this
,導致出現一些奇怪的問題而不知道原因。
5、業務邏輯分散
類組件的第五個問題是業務邏輯過于分散。
下面這個例子中,我要給組件添加一個定時器和一個事件監聽,我們需要把監聽事件卸載 componentDidMount
里面,同時將返回的實例賦值給 class 的實例變量。然后我們還需要在 componentWillUnMount
中拿到實例變量去取消定時器和事件監聽。
componentDidMount() {
// 定時器
this.timer = setTimeout(() => {
// do something
}, 1000)
// 事件監聽
this.listener = DeviceEventEmitter.addListener("key", () => {
// do something
})
}
componentWillUnmount() {
// 取消定時器
this.timer && clearTimeout(this.timer)
// 取消事件監聽
this.listener && this.listener.remove()
}
可以發現,實現一個功能,代碼要寫在不同生命周期函數里面,一點都不聚合,特別的分散,當代碼量上去了之后就會增加維護難度。很可能監聽了一個事件,然后忘記寫移除代碼。
再來看看 React Hooks 的邏輯:
useEffect(() => {
// 定時器
const timer = setTimeout(() => {
// do something
}, 1000)
// 事件監聽
const listener = DeviceEventEmitter.addListener("key", () => {
// do something
})
return () => {
// 取消定時器
timer && clearTimeout(timer)
// 取消事件監聽
listener && listener.remove()
}
}, [])
這里的事件監聽和移除監聽是寫在同一個閉包里面的,作為一個整體進行展示,是不是聚合很多~
6、邏輯復用困難
前面的幾點都是前菜,React Hooks 相對于傳統組件的最大優勢其實是邏輯復用。說到邏輯復用,很多同學會說 Render Props
和 HOC
(高階組件)可以做邏輯復用!那我們看看 類組件 的邏輯復用有多么的慘不忍睹。
復用技術一:Render Props
首先是 Render Props
,有些同學可能不太清楚什么是 render props
。那我這里簡單介紹一下,react 官方文檔是這樣描述的:
什么是 Render Props?這是一種在 React 組件之間使用一個值為函數的 prop 共享代碼的簡單技術。
光看這個介紹有點蒙,相信使用過 RN 的應該都知道 FlatList 吧,其中的 renderItem
就是利用了 render props
技術,將設置給 FlatList 組件的數據源共享給列表中的每個 Item 組件。
<FlatList renderItem={(item) => {
return <Item data={item.data}>
}}></FlatList>
renderItem
是一個函數,item 會被傳遞到相應的 Item 組件中,這就實現了實現了兩個組件之間的數據共享。
更多關于 render props
的說明可以查看官方 Render Props 文檔。
復用技術二:HOC(高階組件)
除了 render props
,第二個大家最常用組件復用技巧就是 HOC,HOC 是 Higher Order Component 的縮寫,意為高階組件。
官方的解釋是:
HOC 是 React 中用于復用組件邏輯的一種高級技巧,具體而言,高階組件是參數為組件,返回值為新組件的函數。
表現形式為:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
higherOrderComponent
這個新函數會對 WrappedComponent
組件進行包裝,注入 props。
react-redux
中的 connect
就是 HOC 的典型應用,用于連接 React 組件與 Redux store,接受數據流、dispatch 更新數據等操作。
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
更多關于 HOC 的說明可以查看官方 高階組件(HOC) 文檔。
那簡單介紹了一下 Render Props 和 HOC,接下來用一個實際例子來對比 Render Props、HOC、Hooks 的邏輯復用代碼的優劣勢。
Render Props 的缺陷:嵌套地獄
首先我們這里想復用監聽 PC瀏覽器窗口大小 的變化邏輯,用 render props 可以這樣寫:
<WindowSize>
{(size) => (<MyComponent windowSize={size}>)}
</WindowSize>
然后,我又想復用監聽鼠標位置的邏輯,我只能這么寫了:
<WindowSize>
{(size) => (
<MousePosition>
{(position) => <MyComponent windowSize={size} mousePosition={position}>}
</Mouse>
)}
</WindowSize>
到這里大家應該看到了問題所在。我再復用一個邏輯,那就的再嵌套一層,一層層嵌套下去,這就是所謂的嵌套地獄。
HOC 的缺陷:可讀性差,容易屬性沖突
同樣一個邏輯復用,用 HOC 可以這樣寫:
export default windowSize(mousePosition(MyComponent))
一行代碼搞定~,感覺很輕松的樣子,但是仔細一看,代碼可讀性并不高,函數嵌套調用,如果再來一個邏輯復用,那么就是 嵌套-嵌套-嵌套….。
問題的重點還不在這里,HOC 最被詬病的是屬性沖突,想象一下,大家都在往組件的 props
上面掛屬性,萬一有個重名的,那就 GG 了!
Hooks 驚艷亮相:秒殺 Render Props 和 HOC
const size = useWindowSize()
const position = useMousePosition()
return <MyComponent windowSize={size} mousePostion={postion}>
React Hooks 直接把邏輯復用代碼平鋪了,避免了嵌套問題,同時代碼可讀性非常高,添加邏輯基本對原有邏輯沒有太大改動。直接將 Render Props 和 HOC 都秒殺了!
到這里想必大家已經對 React Hooks 心動了吧,這就對了,接下來就帶大家一起來看看 Hooks 的常用 API,揭開 React Hooks 的面紗~
1、useState
useState
類似 class 的 this.state
、this.setState
的功能,用于數據存儲,派發更新。
useState 的函數聲明如下,接受一個可選的參數,返回一個數組:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
還是以上面的計數組件為例來看看 類組件 和 函數組件 的寫法:
類組件
class CountComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<View>
<Text>You clicked {count} times</Text>
<Button onPress={() => this.setState(this.state.count + 1)}>Click me</Button>
</View>
);
}
}
函數組件
function CountComponent() {
const [count, setCount] = useState(0);
return (
<View>
<Text>You clicked {count} times</Text>
<Button onPress={() => setCount(count + 1)}>Click me</Button>
</View>
);
}
上面是傳統的類組件、下面這個是借助了 hooks 的函數組件。
正常情況下,每當 CountCompoent
重新渲染時(比如父組件重新渲染了,就會觸發這個組件重新執行), useState
都會重新執行,那么它返回的兩個元素應該都會被重置掉才對,所以 count
的值應該永遠都是 0 !
你們分析的沒錯,正常情況下是這樣的,但是 useState
不是普通函數,他是能夠跟 React 組件生命周期關聯的,只要組件掛載后沒有被銷毀,那么它返回的值一直會被緩存起來。
有人可能會好奇這個值究竟是怎么被緩存起來的,這個問題涉及到 React Hooks 的底層實現,是另一個話題了,我們在這里暫時不討論。大家只需要知道 useState
不是普通函數,而是能夠跟 React 生命周期綁定的鉤子函數就行。
所以我們用 useState
就能夠實現上面 類組件 中 this.state
、this.setState
同樣的功能,是不是簡潔很多。
2、useRef
useRef
類似類組件中實例屬性的功能,用來在組件生命周期內存儲值。
useRef
的函數聲明,它接收一個初始值 initialValue
,返回一個 MutableRefObject
,這個東西其實是一個包裝了 current
屬性的 JS對象,initialValue
初始值會直接賦值給 current
。:
interface MutableRefObject<T> {
current: T;
}
function useRef<T>(initialValue: T): MutableRefObject<T>;
useRef
返回的 JS對象 在組件的整個生命周期內持續存在,當組件重新渲染時對象不會被垃圾回收掉(普通變量就會被垃圾回收,因為函數作用域已經出棧了),我們可以通過 current
屬性存儲、讀取緩存值。
那什么值需要在組件整個生命周期內存儲呢?典型的就是組件 ref 實例,useRef
也正是因此而得名。下面用 useRef
存儲了 TextInput
ref 實例,當我們點擊按鈕的時候,就可以拿到這個對象,通過 current
訪問實例,調用 onFocus
方法讓輸入框獲得焦點:
function MyComponent() {
const inputRef = useRef(null)
const onButtonClick = () => {
inputRef.current.onFocus()
};
return (
<View>
<TextInput ref={inputRef}/>
<Button onPress={onButtonClick}>focus</Button>
</View>
);
}
3、useEffect
useEffect
用于執行副作用,可以把 useEffect
看做類組件中 componentDidMount
,componentDidUpdate
和 componentWillUnmount
這三個生命周期函數的組合。
那什么是副作用?
副作用是函數式編程中的概念,與之對立的概念是”純函數“,純函數的特點就是相同的輸入值時,需產生相同的輸出,這個輸出不光是返回值,還包括是否影響外部的狀態,比如全局變量、DOM結構、日志輸出、網絡請求等等。如果一個函數不滿足這個特質,那么我們就說它含有副作用。
因此,React 中的 useEffect
,就是用于執行副作用的函數,諸如網絡請求、事件監聽、DOM修改等操作。如果你的動作不具備副作用,可能就沒必要放到 useEffect
中了。(比較抽象,大家可以后面再實踐中慢慢體會)
useEffect
的函數聲明如下:接受兩個參數,第一個參數是一個函數,我們稱之為副作用回調函數,會在副作用觸發時自動執行,該函數可以再返回一個函數做副作用的清除工作;第二個參數是一個數組,用于給出 Effect 的依賴項,只要這個數組中的變量任意一個發生變化,就會觸發副作用,執行第一個函數參數:
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
下面我們用 useEffect
模擬一下 React 組件的聲明周期函數:
模擬 componentDidMount
當依賴數組傳一個空數組,那么 useEffect 副作用回調只會在第一次掛載時執行。
下面的例子是在組件掛載時添加一個定時器:
useEffect(() => {
// 只會在組件第一次掛載時執行
this.timer = setTimeout(Function, 1000)
}, [])
這個時候副作用回調函數就相當于 componentDidMount
的生命周期函數了。
模擬 componentWillUnmount
useEffect
副作用回調函數可以有一個返回函數,這個函數會在組件銷毀的時候執行。
上面我們添加了定時器,那么在組件卸載時就需要進行清除工作:
useEffect(() => {
// 添加定時器
this.timer = setTimeout(Function, 1000)
return () => {
// 清除定時器
this.timer && clearTimeout(this.timer)
}
}, [])
副作用回調函數返回的函數,就相當于 componentWillUnmount
生命周期函數了。
模擬 componentDidUpdate
當依賴數組如果不傳,那么組件掛載、更新都會執行副作用回調函數。
但是 componentDidUpdate
只有在組件更新時才會調用,掛載時是不會執行的,所以要模擬 componentDidUpdate
還需要借助 useRef
Hook。
考慮定時器需要從父組件接受等待時間參數的場景:
// 初始值為 true
const isFirst = useRef(true)
useEffect(() => {
if (!isFirst.current) {
// 會在組件更新時執行
this.timer = setTimeout(Function, props.delay)
return () => {
this.timer && clearTimeout(this.timer)
}
}
// 執行一次之后設置為 false
isFirst.current = false
})
useEffect 依賴數組的應用
上面的代碼邏輯其實是有問題的,what?細心的同事應該已經發現了~,主要有以下兩個問題:
- 這個定時器在組件掛載時是不會開啟的,只有在更新時才會觸發;
- 每次組件更新,定時器都會無條件的銷毀重設,沒有條件約束,影響性能。
componentDidUpdate
通常像下面這樣處理:
componentDidUpdate(prevProps) {
if (this.props.delay !== prevProps.delay) {
this.timer = setTimeout(Function, props.delay);
}
}
但是 hook 中并不能像 類組件 一樣通過 prevProps
訪問上一次的 props
值,如何做 props.delay
的對比?
Hooks 考慮到這種場景,已經將這個功能內置到其 API 中去了,通過第二個數組參數進行控制,上面的代碼可以這樣改造:
useEffect(() => {
// 掛載時、props.delay 更新時執行
const timer = setTimeout(Function, props.delay)
return () => {
timer && clearTimeout(timer)
}
}, [props.delay])
useEffect
內部緩存了上一次的狀態,在組件重新渲染的時候,會自動對數組中的元素進行一次淺比較,任意一個元素變更都會執行副作用回調函數。
讓我們來做一個小結:
- Hook 的最大特點就是跟 React 組件的生命周期關聯,這也是 Hooks 能夠讓函數組件能夠管理狀態的根本;
-
useState
、useRef
、useEffect
是 React 最基本的三個 Hook,掌握了這三個 Hook 的應用基本就可以開始擼代碼了; - React Hooks API 中目前總共有 13 個 Hooks,用法同上面講到的 Hook 用法都差不多,大家可以后期慢慢深入了解。
你以為這就結束了嗎,是不是已經被 React Hooks 打動了呢?接下來才是真正讓你傾心的時刻,接著往下看~
React Hooks 最強大功能當屬自定義 Hook,它是 React Hooks 風靡的關鍵。
什么是自定義 Hook?自定義 Hook 是一個函數,其名稱約定以 “use” 開頭,函數內部可以調用其他的 Hook
當我們想在兩個函數之間共享邏輯時,我們會把它提取到第三個函數中。而組件和 Hook 都是函數,所以也同樣適用這種方式。我們可以將共享邏輯提取到自定義 Hook 中去,前面提到的 useWindowSize
、useMousePosition
都屬于自定義 Hook,他們分別封裝了窗口大小變化、鼠標位置變化的邏輯。
為了了解自定義 hook,簡單看看我們前面提到的 useWindowSize
自定義 Hook 的代碼實現:
const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({ width: 0, height: 0 })
useEffect(() => {
const onWindowResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
})
}
window.addEventListener('resize', onWindowResize)
return () => {
window.removeEventListener('resize', onWindowResize)
}
}, [])
return windowSize
}
到這里有的人可能并沒有看出 Hooks 的優勢,因為沒有對比。我們以日常最常見的網絡請求為例,看看 Hooks 是怎么讓大家能夠早點下班的~
class 版本的網絡請求:
export default class MyPage extends React.Component {
request = null // fetch 實例
constructor(props) {
super(props);
this.state = {
data: null,
errorMsg: null,
errorCode: null,
loading: false
}
}
componentDidMount() {
// 組件掛載,發起網絡請求
this.request = this.requestData()
}
componentWillUnmount() {
// 組件銷毀,取消網絡請求
this.request.cancel()
}
requestData = () => {
this.setState({
loading: true
})
return fetch("https://xxx").then((result) => {
this.setState({
data: result.data,
errorMsg: null,
errorCode: null
})
}).catch((error) => {
this.setState({
errorMsg: error.message,
errorCode: error.code
})
}).finally(() => {
this.setState({
loading: false
})
})
}
}
render() {
return <View>
{this.state.loading && <Loading/>}
{(!this.state.loading && this.state.errorMsg) && <Error msg={this.state.errorMsg} code={this.state.code}></Error>}
{(!this.state.loading && !this.state.errorMsg) && <Content data={this.state.data}></Content>}
</View>
}
是不是感覺這種模板代碼每個頁面都有,簡直是煩死了…,那為什么不封裝一下呢?因為不好封裝!
這段邏輯其實是把 狀態邏輯 跟 UI顯示 耦合在一起了,要分開其實挺難的,不管是 render props
還是 HOC
,封裝出來的效果都差強人意。而拆解狀態和UI正是 Hooks 的強項。
Hooks 版本的網絡請求:
export default function MyPage() {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [errorMsg, setErrorMsg] = useState(null)
const [errorCode, setErrorCode] = useState(null)
const request = useRef(null)
const requestData = useCallback(() => {
setLoading(true);
return fetch("https://xxx")
.then((result) => {
setData(result.data);
setErrorMsg(null);
setErrorCode(null);
})
.catch((error) => {
setErrorMsg(error.message);
setErrorCode(error.code);
})
.finally(() => {
setLoading(false);
});
}, []);
useEffect(() => {
request.current = requestData()
return () => {
request.current.cancel()
}
}, [])
return <View>
{loading && <Loading/>}
{(!loading && errorMsg) && <Error msg={errorMsg} code={code}></Error>}
{(!loading && !errorMsg) && <Content data={data}></Content>}
</View>
}
單從代碼數量來看, hooks 只是比 類組件 中的網絡請求少一些代碼而已,并沒有太大優勢對吧,接下來就是見證奇跡的時刻~
咱們自定義一個 Hook,取名為 useRequest
,這個自定義 Hook 接收一個 url 參數,返回網絡請求的最終結果,包括數據、加載狀態、錯誤信息等等。代碼如下:
const useRequest = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState(null);
const [errorCode, setErrorCode] = useState(null);
const request = useRef(null);
const requestData = useCallback(() => {
setLoading(true);
return fetch(url)
.then((result) => {
setData(result.data);
setErrorMsg(null);
setErrorCode(null);
})
.catch((error) => {
setErrorMsg(error.message);
setErrorCode(error.code);
})
.finally(() => {
setLoading(false);
});
}, [url]);
useEffect(() => {
request.current = requestData();
return () => {
request.current.cancel();
};
}, []);
return { data, loading, errorMsg, errorCode }
};
可以看到這里面的代碼都是從上面挪過來的,只有 url 是從外面傳進來的,這也是 Hooks 的強大之處,就跟抽取復用函數一樣簡單。
那我們怎么使用呢?在我們的 MyPage
中這樣使用:
export default function MyPage() {
const { data, loading, errorMsg, errorCode } = useRequest("https://xxx")
return <View>
{loading && <Loading/>}
{(!loading && errorMsg) && <Error msg={errorMsg} code={code}></Error>}
{(!loading && !errorMsg) && <Content data={data}></Content>}
</View>
}
簡直不要太簡單,可以早點下班了~,到此,相信你已經徹底愛上了 React Hooks,那就不要再靦腆了,直接表白吧~~~
基于 Hooks 這種強大的能力,我們可以抽象大量自定義 Hooks,讓代碼更加簡單,同時也不會增加嵌套層級。
到這里分享就結束了,這篇文章主要跟大家分享 React Hooks 的入門篇,后續還會有實戰篇,下次再會~
本文原創,轉載注明出處