摘要:最近官方在大會(huì)上宣布內(nèi)測(cè)將引入。所以我們有必要了解,以及由此引發(fā)的疑問(wèn)。在進(jìn)一步了解之前,我們需要先快速的了解一些基本的的用法。如何解決狀態(tài)有關(guān)的邏輯的重用和共享問(wèn)題。
“大家好,我是谷阿莫,今天要將的是一個(gè)...”,哈哈哈,看到這個(gè)題我就想到這個(gè)開頭。最近react 官方在 2018 ReactConf 大會(huì)上宣布 React v16.7.0-alpha(內(nèi)測(cè)) 將引入 Hooks。所以我們有必要了解 Hooks,以及由此引發(fā)的疑問(wèn)。
當(dāng)然,學(xué)習(xí)的最好、最直接的方法就是看文檔,所以我也非常建議大家去看文檔學(xué)習(xí),而且還是官方的文檔而不是中文版的文檔。本文也是樓主在學(xué)習(xí)過(guò)后的一些總結(jié)與思考,樓主會(huì)把最近學(xué)習(xí)到的由淺入深,循序漸進(jìn),盡可能簡(jiǎn)潔的分享給大家,希望對(duì)大家有幫助。不足之處可在評(píng)論區(qū)補(bǔ)充,本文講從以下幾個(gè)大方面來(lái)展開:
為什么引入Hooks
Hooks使用和注意事項(xiàng)
Hooks的如何解決了已存在的問(wèn)題
引入Hooks引發(fā)的疑問(wèn)
為什么引入Hooks?react官方給出的動(dòng)機(jī)是用來(lái)解決長(zhǎng)時(shí)間使用和維護(hù)react過(guò)程中遇到的一些難以避免的問(wèn)題。比如:
難以重用和共享組件中的與狀態(tài)相關(guān)的邏輯
邏輯復(fù)雜的組件難以開發(fā)與維護(hù),當(dāng)我們的組件需要處理多個(gè)互不相關(guān)的 local state 時(shí),每個(gè)生命周期函數(shù)中可能會(huì)包含著各種互不相關(guān)的邏輯在里面。
類組件中的this增加學(xué)習(xí)成本,類組件在基于現(xiàn)有工具的優(yōu)化上存在些許問(wèn)題。
由于業(yè)務(wù)變動(dòng),函數(shù)組件不得不改為類組件等等。
在進(jìn)一步了解之前,我們需要先快速的了解一些基本的 Hooks 的用法。
快速了解 Hooks 的使用Hooks讓我們的函數(shù)組件擁有了類似類組件的特性,比如local state、lifecycle,而且還解決了上面提到的一系列問(wèn)題,它是如何解決這些問(wèn)題的,下面會(huì)在一一指出。首先來(lái)快速的看看Hoos的使用,這里講最主要的兩個(gè) Hooks :useState 和 useEffect。先看一個(gè)你可能看過(guò)很多遍的例子
import { useState, useEffect } from "react"; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return (useState{count}
); }
useState 這個(gè)方法可以為我們的函數(shù)組件帶來(lái) local state,它接收一個(gè)用于初始 state 的值,返回一對(duì)變量
const [count, setCount] = useState(0); // 等價(jià)于 var const = useState(0)[0]; // 該state var setConst = useState(0)[1]; // 修改該state的方法useEffect
useEffect 可以利用我們組件中的 local state 進(jìn)行一些帶有副作用的操作
useEffect(() => { document.title = `You clicked ${count} times`; });
useEffect 中還可以通過(guò)傳入第二個(gè)參數(shù)來(lái)決定是否執(zhí)行里面的操作來(lái)避免一些不必要的性能損失,只要第二個(gè)參數(shù)數(shù)組中的成員的值沒有改變,就會(huì)跳過(guò)此次執(zhí)行。如果傳入一個(gè)空數(shù)組 [ ],那么該 effect 只會(huì)在組件 mount 和 unmount 時(shí)期執(zhí)行。
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 如果count沒有改變,就跳過(guò)此次執(zhí)行
useEffect 中還可以通過(guò)讓函數(shù)返回一個(gè)函數(shù)來(lái)進(jìn)行一些清理操作(clean up),比如取消訂閱等
useEffect(() => { api.subscribe(theId); return () => { api.unsubscribe(theId) //clean up } });
useEffect 什么時(shí)候執(zhí)行? 它會(huì)在組件 mount 和 unmount 以及每次重新渲染的時(shí)候都會(huì)執(zhí)行,也就是會(huì)在 componentDidMount、componentDidUpdate、componentWillUnmount 這三個(gè)時(shí)期執(zhí)行。
清理函數(shù)(clean up)什么時(shí)候執(zhí)行? 它會(huì)在前一次 effect執(zhí)行后,下一次 effect 將要執(zhí)行前,以及 Unmount 時(shí)期執(zhí)行
注意事項(xiàng)我們只能在 函數(shù)組件 中使用 Hooks,我們也可以在一個(gè)組件中使用多組 Hooks。比如:
function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { API.subscribe(props.friend.id); return () => { API.unsubscribe(props.friend.id); }; }); return isOnline }
但是這里有一點(diǎn)需要我們注意的就是 我們只能在頂層代碼(Top Level)中調(diào)用 Hooks,不能在循環(huán)或判斷語(yǔ)句等里面調(diào)用,這樣是為了讓我們的 Hooks 在每次渲染的時(shí)候都會(huì)按照 相同的順序 調(diào)用,因?yàn)檫@里有一個(gè)跟關(guān)鍵的問(wèn)題,那就是 useState 需要依賴參照第一次渲染的調(diào)用順序來(lái)匹配對(duì)于的state,否則 useState 會(huì)無(wú)法正確返回它對(duì)于的state。
Hooks 解決的問(wèn)題好了,知道了 Hooks 基本使用后,我們就可以來(lái)了解 Hooks 是怎么解決 react 長(zhǎng)期存在的問(wèn)題的。
如何解決 狀態(tài)有關(guān)的邏輯(stateful logic) 的重用和共享問(wèn)題。過(guò)去對(duì)于類似問(wèn)題的解決方案主要有兩個(gè):
Render Props 通過(guò)props接受一個(gè)返回react element的函數(shù),來(lái)動(dòng)態(tài)決定自己要渲染的結(jié)果;
( Hello {data.target}
)}/>
還有就是Higher-Order Components 以一種類似 工廠模式 的方式去生產(chǎn)出具有相同或類似邏輯的組件。
function getComponent(WrappedComponent) { return class extends React.Component { constructor(props) { super(props); } componentDidMount() { // doSomething } componentWillUnmount() { // doSomething } render() { return; } }; }
但是無(wú)論是哪一種方法都會(huì)造成組件數(shù)量增多,組件樹結(jié)構(gòu)的修改,而且有可能出現(xiàn)組件嵌套地獄(wrapper hell)的情況?,F(xiàn)在 React 通過(guò) custom Hooks 來(lái)解決這個(gè)問(wèn)題。
custom Hookscustom Hooks 并不是一個(gè)api,而是一個(gè)規(guī)則。具體實(shí)現(xiàn)就是通過(guò)一個(gè)函數(shù)來(lái)封裝跟狀態(tài)有關(guān)的邏輯(stateful logic),將這些邏輯從組件中抽取出來(lái)。在這個(gè)函數(shù)中我們可以使用其他的 Hooks,也可以多帶帶進(jìn)行測(cè)試,甚至將它貢獻(xiàn)給社區(qū)。
import { useState, useEffect } from "react"; function useCount() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return count }
比如上面的一個(gè)例子,他就是一個(gè) custom Hooks,提取了對(duì) count 的操作。這里需要遵循一個(gè)約定,命名要用 use*,這是為了方便我們區(qū)分,利于我們維護(hù)。可以看到他其實(shí)就是一個(gè)函數(shù),我們可以在現(xiàn)有的所有其他組件中引用它
function CountStatus() { const count = useCount(); return count; }
這里的核心概念就是將邏輯提取出來(lái)封裝在 custom Hooks,然后可以在任何的其他組件中共享這部分邏輯,也可以貢獻(xiàn)給社區(qū)。所以我也預(yù)測(cè)在不久的將來(lái),會(huì)出現(xiàn)很多的充滿想象力的各種用途的 custom Hooks 在社區(qū)中出現(xiàn),極大的提高我們的開發(fā)效率。
具有復(fù)雜邏輯的組件的開發(fā)和維護(hù)前面我們也提到,我們的組件可能會(huì)隨著開發(fā)的進(jìn)行變得越來(lái)越復(fù)雜,要處理越來(lái)越多的 local State,那么在組件的生命周期函數(shù)中就會(huì)充斥著各種互不相關(guān)的邏輯,這里需要引入官方的比較復(fù)雜的例子,先看基于以前類組件的情況:
class FriendStatusWithCounter extends React.Component { constructor(props) { super(props); this.state = { count: 0, isOnline: null }; this.handleStatusChange = this.handleStatusChange.bind(this); } componentDidMount() { document.title = `You clicked ${this.state.count} times`; ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } // ...
經(jīng)過(guò) Hook 改造后:
function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); function handleStatusChange(status) { setIsOnline(status.isOnline); } // ... }
狀態(tài)和相關(guān)的處理邏輯可以按照功能進(jìn)行劃分,不必散落在各個(gè)生命周期中,大大降低了開發(fā)和維護(hù)的難度。除了這幾個(gè)hooks還有其他額外的hooks,在此繼續(xù)了解 Hooks API Reference
伴隨 Hooks 的一些思考hooks讓我們的函數(shù)組件的功能得到了擴(kuò)充,擁有了和類組件相似的功能,甚至避免了類組件存在的各種問(wèn)題,那么就會(huì)出現(xiàn)各種的疑問(wèn),比如
Hooks 引進(jìn)后, 函數(shù)組件 和 類組件 該如何選擇?官方關(guān)于類似的問(wèn)題的答復(fù)是:
Our goal is for Hooks to cover all use cases for classes as soon as possible. There are no Hook equivalents to the uncommon getSnapshotBeforeUpdate and componentDidCatch lifecycles yet, but we plan to add them soon.It is a very early time for Hooks, so some integrations like DevTools support or Flow/TypeScript typings may not be ready yet. Some third-party libraries might also not be compatible with Hooks at the moment.
官方的目標(biāo)是盡可能快的讓 Hooks 去覆蓋所有的類組件案例,但是現(xiàn)在 Hooks 還處于一個(gè)非常早的階段,各種調(diào)試工具、第三方庫(kù)等都還沒有做好對(duì) Hooks 的支持,而且目前也沒有可以取代類組件中 getSnapshotBeforeUpdate 和 componentDidCatch 生命做起的 Hooks,不過(guò)很快會(huì)加上他們??偟膩?lái)時(shí)就是鼓勵(lì)大家在以后使用 Hooks,對(duì)于已存在的類組件不必大規(guī)模的去重寫,Hooks及Hooks的生態(tài)會(huì)繼續(xù)完善,請(qǐng)期待。
Hooks 是否可以代替 render-props 和 higher-order components ?前面我們也提到,hooks可以解決后者帶來(lái)的各種問(wèn)題,那么 hooks 是否可以代替后者呢?官方的回答:
Often, render props and higher-order components render only a single child. We think Hooks are a simpler way to serve this use case. There is still a place for both patterns (for example, a virtual scroller component might have a renderItem prop, or a visual container component might have its own DOM structure). But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.
大概意思就是,在大多數(shù)案例下,hooks 足夠應(yīng)付且更適合,所以優(yōu)先考慮 hooks。
這是我看到 hooks 后比較關(guān)心的兩個(gè)問(wèn)題,如果大家想了解更多的問(wèn)題的話可以到 Hooks FAQ 了解。如果有什么不足或要補(bǔ)充的地方,歡迎評(píng)論區(qū)提出。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98925.html
摘要:簡(jiǎn)介是的新增特性。我們統(tǒng)一把這些操作稱為副作用,或者簡(jiǎn)稱為作用。由于副作用函數(shù)是在組件內(nèi)聲明的,所以它們可以訪問(wèn)到組件的和。副作用函數(shù)還可以通過(guò)返回一個(gè)函數(shù)來(lái)指定如何清除副作用。目前為止,有兩種主流方案來(lái)解決這個(gè)問(wèn)題高階組件和。 Hook 簡(jiǎn)介 Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。 us...
摘要:他們的應(yīng)用是比較復(fù)雜的,組件樹也是非常龐大,假設(shè)有一千個(gè)組件要渲染,每個(gè)耗費(fèi)一千個(gè)就是由于是單線程的,這里都在努力的干活,一旦開始,中間就不會(huì)停。 悄悄的, React v16.7 發(fā)布了。 React v16.7: No, This Is Not The One With Hooks. showImg(https://segmentfault.com/img/bVblq9L?w=97...
摘要:前言樓主最近在整理的一些資料,為項(xiàng)目重構(gòu)作準(zhǔn)備,下午整理成了這篇文章。給傳入的是一個(gè)初始值,比如,這個(gè)按鈕的最初要顯示的是。取代了提供了一個(gè)統(tǒng)一的。 showImg(https://segmentfault.com/img/bVbpUle?w=900&h=550); Hooks are a new addition in React 16.8. They let you use sta...
摘要:前言樓主最近在整理的一些資料,為項(xiàng)目重構(gòu)作準(zhǔn)備,下午整理成了這篇文章。給傳入的是一個(gè)初始值,比如,這個(gè)按鈕的最初要顯示的是。取代了提供了一個(gè)統(tǒng)一的。 showImg(https://segmentfault.com/img/bVbpUle?w=900&h=550); Hooks are a new addition in React 16.8. They let you use sta...
摘要:所以我們做的事情其實(shí)就是,聲明了一個(gè)狀態(tài)變量,把它的初始值設(shè)為,同時(shí)提供了一個(gè)可以更改的函數(shù)。 你還在為該使用無(wú)狀態(tài)組件(Function)還是有狀態(tài)組件(Class)而煩惱嗎? ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。 你還在為搞不清使用哪個(gè)生命周期鉤子函數(shù)而日夜難眠嗎? ——擁有了Hooks,生命周期鉤子函數(shù)可以先丟一邊了。 你在還...
閱讀 1308·2021-11-23 09:51
閱讀 3426·2021-09-06 15:00
閱讀 1000·2021-08-16 10:57
閱讀 1385·2019-08-30 12:46
閱讀 948·2019-08-29 12:22
閱讀 1617·2019-08-29 11:07
閱讀 3162·2019-08-26 11:23
閱讀 2993·2019-08-23 15:14