摘要:最近官方在大會上宣布內測將引入。所以我們有必要了解,以及由此引發的疑問。在進一步了解之前,我們需要先快速的了解一些基本的的用法。如何解決狀態有關的邏輯的重用和共享問題。
“大家好,我是谷阿莫,今天要將的是一個...”,哈哈哈,看到這個題我就想到這個開頭。最近react 官方在 2018 ReactConf 大會上宣布 React v16.7.0-alpha(內測) 將引入 Hooks。所以我們有必要了解 Hooks,以及由此引發的疑問。
當然,學習的最好、最直接的方法就是看文檔,所以我也非常建議大家去看文檔學習,而且還是官方的文檔而不是中文版的文檔。本文也是樓主在學習過后的一些總結與思考,樓主會把最近學習到的由淺入深,循序漸進,盡可能簡潔的分享給大家,希望對大家有幫助。不足之處可在評論區補充,本文講從以下幾個大方面來展開:
為什么引入Hooks
Hooks使用和注意事項
Hooks的如何解決了已存在的問題
引入Hooks引發的疑問
為什么引入Hooks?react官方給出的動機是用來解決長時間使用和維護react過程中遇到的一些難以避免的問題。比如:
難以重用和共享組件中的與狀態相關的邏輯
邏輯復雜的組件難以開發與維護,當我們的組件需要處理多個互不相關的 local state 時,每個生命周期函數中可能會包含著各種互不相關的邏輯在里面。
類組件中的this增加學習成本,類組件在基于現有工具的優化上存在些許問題。
由于業務變動,函數組件不得不改為類組件等等。
在進一步了解之前,我們需要先快速的了解一些基本的 Hooks 的用法。
快速了解 Hooks 的使用Hooks讓我們的函數組件擁有了類似類組件的特性,比如local state、lifecycle,而且還解決了上面提到的一系列問題,它是如何解決這些問題的,下面會在一一指出。首先來快速的看看Hoos的使用,這里講最主要的兩個 Hooks :useState 和 useEffect。先看一個你可能看過很多遍的例子
import { useState, useEffect } from "react"; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return (useState{count}
); }
useState 這個方法可以為我們的函數組件帶來 local state,它接收一個用于初始 state 的值,返回一對變量
const [count, setCount] = useState(0); // 等價于 var const = useState(0)[0]; // 該state var setConst = useState(0)[1]; // 修改該state的方法useEffect
useEffect 可以利用我們組件中的 local state 進行一些帶有副作用的操作
useEffect(() => { document.title = `You clicked ${count} times`; });
useEffect 中還可以通過傳入第二個參數來決定是否執行里面的操作來避免一些不必要的性能損失,只要第二個參數數組中的成員的值沒有改變,就會跳過此次執行。如果傳入一個空數組 [ ],那么該 effect 只會在組件 mount 和 unmount 時期執行。
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 如果count沒有改變,就跳過此次執行
useEffect 中還可以通過讓函數返回一個函數來進行一些清理操作(clean up),比如取消訂閱等
useEffect(() => { api.subscribe(theId); return () => { api.unsubscribe(theId) //clean up } });
useEffect 什么時候執行? 它會在組件 mount 和 unmount 以及每次重新渲染的時候都會執行,也就是會在 componentDidMount、componentDidUpdate、componentWillUnmount 這三個時期執行。
清理函數(clean up)什么時候執行? 它會在前一次 effect執行后,下一次 effect 將要執行前,以及 Unmount 時期執行
注意事項我們只能在 函數組件 中使用 Hooks,我們也可以在一個組件中使用多組 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 }
但是這里有一點需要我們注意的就是 我們只能在頂層代碼(Top Level)中調用 Hooks,不能在循環或判斷語句等里面調用,這樣是為了讓我們的 Hooks 在每次渲染的時候都會按照 相同的順序 調用,因為這里有一個跟關鍵的問題,那就是 useState 需要依賴參照第一次渲染的調用順序來匹配對于的state,否則 useState 會無法正確返回它對于的state。
Hooks 解決的問題好了,知道了 Hooks 基本使用后,我們就可以來了解 Hooks 是怎么解決 react 長期存在的問題的。
如何解決 狀態有關的邏輯(stateful logic) 的重用和共享問題。過去對于類似問題的解決方案主要有兩個:
Render Props 通過props接受一個返回react element的函數,來動態決定自己要渲染的結果;
( Hello {data.target}
)}/>
還有就是Higher-Order Components 以一種類似 工廠模式 的方式去生產出具有相同或類似邏輯的組件。
function getComponent(WrappedComponent) { return class extends React.Component { constructor(props) { super(props); } componentDidMount() { // doSomething } componentWillUnmount() { // doSomething } render() { return; } }; }
但是無論是哪一種方法都會造成組件數量增多,組件樹結構的修改,而且有可能出現組件嵌套地獄(wrapper hell)的情況。現在 React 通過 custom Hooks 來解決這個問題。
custom Hookscustom Hooks 并不是一個api,而是一個規則。具體實現就是通過一個函數來封裝跟狀態有關的邏輯(stateful logic),將這些邏輯從組件中抽取出來。在這個函數中我們可以使用其他的 Hooks,也可以多帶帶進行測試,甚至將它貢獻給社區。
import { useState, useEffect } from "react"; function useCount() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return count }
比如上面的一個例子,他就是一個 custom Hooks,提取了對 count 的操作。這里需要遵循一個約定,命名要用 use*,這是為了方便我們區分,利于我們維護。可以看到他其實就是一個函數,我們可以在現有的所有其他組件中引用它
function CountStatus() { const count = useCount(); return count; }
這里的核心概念就是將邏輯提取出來封裝在 custom Hooks,然后可以在任何的其他組件中共享這部分邏輯,也可以貢獻給社區。所以我也預測在不久的將來,會出現很多的充滿想象力的各種用途的 custom Hooks 在社區中出現,極大的提高我們的開發效率。
具有復雜邏輯的組件的開發和維護前面我們也提到,我們的組件可能會隨著開發的進行變得越來越復雜,要處理越來越多的 local State,那么在組件的生命周期函數中就會充斥著各種互不相關的邏輯,這里需要引入官方的比較復雜的例子,先看基于以前類組件的情況:
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 }); } // ...
經過 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); } // ... }
狀態和相關的處理邏輯可以按照功能進行劃分,不必散落在各個生命周期中,大大降低了開發和維護的難度。除了這幾個hooks還有其他額外的hooks,在此繼續了解 Hooks API Reference
伴隨 Hooks 的一些思考hooks讓我們的函數組件的功能得到了擴充,擁有了和類組件相似的功能,甚至避免了類組件存在的各種問題,那么就會出現各種的疑問,比如
Hooks 引進后, 函數組件 和 類組件 該如何選擇?官方關于類似的問題的答復是:
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.
官方的目標是盡可能快的讓 Hooks 去覆蓋所有的類組件案例,但是現在 Hooks 還處于一個非常早的階段,各種調試工具、第三方庫等都還沒有做好對 Hooks 的支持,而且目前也沒有可以取代類組件中 getSnapshotBeforeUpdate 和 componentDidCatch 生命做起的 Hooks,不過很快會加上他們。總的來時就是鼓勵大家在以后使用 Hooks,對于已存在的類組件不必大規模的去重寫,Hooks及Hooks的生態會繼續完善,請期待。
Hooks 是否可以代替 render-props 和 higher-order components ?前面我們也提到,hooks可以解決后者帶來的各種問題,那么 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.
大概意思就是,在大多數案例下,hooks 足夠應付且更適合,所以優先考慮 hooks。
這是我看到 hooks 后比較關心的兩個問題,如果大家想了解更多的問題的話可以到 Hooks FAQ 了解。如果有什么不足或要補充的地方,歡迎評論區提出。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98925.html
摘要:簡介是的新增特性。我們統一把這些操作稱為副作用,或者簡稱為作用。由于副作用函數是在組件內聲明的,所以它們可以訪問到組件的和。副作用函數還可以通過返回一個函數來指定如何清除副作用。目前為止,有兩種主流方案來解決這個問題高階組件和。 Hook 簡介 Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。 us...
摘要:他們的應用是比較復雜的,組件樹也是非常龐大,假設有一千個組件要渲染,每個耗費一千個就是由于是單線程的,這里都在努力的干活,一旦開始,中間就不會停。 悄悄的, React v16.7 發布了。 React v16.7: No, This Is Not The One With Hooks. showImg(https://segmentfault.com/img/bVblq9L?w=97...
摘要:前言樓主最近在整理的一些資料,為項目重構作準備,下午整理成了這篇文章。給傳入的是一個初始值,比如,這個按鈕的最初要顯示的是。取代了提供了一個統一的。 showImg(https://segmentfault.com/img/bVbpUle?w=900&h=550); Hooks are a new addition in React 16.8. They let you use sta...
摘要:前言樓主最近在整理的一些資料,為項目重構作準備,下午整理成了這篇文章。給傳入的是一個初始值,比如,這個按鈕的最初要顯示的是。取代了提供了一個統一的。 showImg(https://segmentfault.com/img/bVbpUle?w=900&h=550); Hooks are a new addition in React 16.8. They let you use sta...
摘要:所以我們做的事情其實就是,聲明了一個狀態變量,把它的初始值設為,同時提供了一個可以更改的函數。 你還在為該使用無狀態組件(Function)還是有狀態組件(Class)而煩惱嗎? ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。 你還在為搞不清使用哪個生命周期鉤子函數而日夜難眠嗎? ——擁有了Hooks,生命周期鉤子函數可以先丟一邊了。 你在還...
閱讀 1302·2021-11-23 09:51
閱讀 3413·2021-09-06 15:00
閱讀 993·2021-08-16 10:57
閱讀 1378·2019-08-30 12:46
閱讀 943·2019-08-29 12:22
閱讀 1612·2019-08-29 11:07
閱讀 3157·2019-08-26 11:23
閱讀 2989·2019-08-23 15:14