React Hooks比你想象的更強大。css
如今,咱們將探索和開發一個自定義Hook來管理全局狀態 - 比Redux更容易使用的方法,而且比Context API更高效。git
若是你已經很熟悉React Hooks,那麼能夠直接跳過這部分。github
useState()npm
在Hooks以前,功能組件沒有狀態。如今,使用useState(),咱們可讓功能組件擁有狀態。編程
useState()會返回一個數組。上面數組的 第一項是一個能夠訪問狀態值的變量。 第二項是一個可以更新組件狀態,並且影響dom變化的函數。useEffect()json
相似Component組件,使用生命週期方法來管理反作用,例如componentDidMount()。useEffect() 函數容許您在函數組件中執行反作用。數組
默認狀況下,useEffect在每次完成渲染後運行。可是,您能夠選擇僅在某些值發生更改時觸發它,並將一個數組做爲第二個可選參數傳遞。dom
要得到與 componentDidMount() 相同的結果,咱們能夠發送一個空數組。空數組不會改變,useEffect只會運行一次。函數式編程
共享states函數
咱們能夠看到Hooks狀態與類組件狀態徹底相同。組件的每一個實例都有本身的狀態。
爲了組件之間共享狀態,咱們將建立一個自定義Hook。
這個想法是建立一個監聽器數組,只有一個狀態對象。每當一個組件更改狀態時,全部訂閱的組件都會觸發其 setState() 函數並進行更新。咱們能夠經過調用自定義Hook中的 useState() 來實現。咱們將 setState() 函數添加到一個監聽器數組,並返回一個函數用來更新state 和 運行全部監聽器函數。
如今已經有了 use-global-hook 這個npm包,您能夠經過包文檔中的示例瞭解如何使用它。可是,從如今開始,咱們將專一於它是怎麼實現的。
我想在第一個版本中改進的內容:
我想在卸載組件時從數組中刪除監聽器。
我想讓它更通用,能夠在其餘項目中使用。
我想經過參數設置 initialState。
我想使用更多函數式編程。
在組件卸載以前調用一個函數
咱們瞭解到,使用空數組調用 useEffect(function,[])與componentDidMount() 具備相同的用途。可是,若是第一個參數中使用的函數返回另外一個函數,則第二個函數將在卸載組件以前觸發。徹底像 componentWillUnmount()。
這是從監聽器數組中刪除組件的理想位置。
除了最後的修改,咱們還將:
將React設置爲參數,再也不導入它。
不導出 customHook,而是導出根據 initialState 參數返回新 customHook()。
建立一個包含state和 setState() 函數的store對象。
替換 setState() 和 useCustom() 的上下文爲store。
由於咱們如今有一個更通用的Hook,咱們必須在store文件中設置它。
若是您曾經使用過複雜的狀態管理庫,那麼您就知道直接在組件中操做全局狀態並非最好的作法。
最好的方法是,經過建立操做狀態的action來分離業務邏輯。出於這個緣由,我但願咱們的解決方案的最後一個版本中,組件不能訪問setState()去操做狀態,而是經過actions。
爲了解決這個問題,咱們的 useGlobalHook(React,initialState,actions) 函數將接收一個action對象做爲第三個參數。關於這一點,我想補充一些東西:
Actions將有權訪問store對象。所以,action能夠使用 store.state 讀取狀態,經過store.setState() 寫入狀態,甚至使用 state.actions 調用其餘操做。
對於組織,actions對象能夠包含其餘actions的子對象。所以,您可能調用 actions.addToCounter(amount) ,**或者一個action子對象, 調用actions.counter.add(amount) **。
如下是NPM包use-global-hook中的內容。
src/styles.css
src/index.js
src/store/index.js
src/components/Counters.js
src/components/Repos.js
src/components/SearchForm.js
src/actions/counter.js
src/actions/github.js
src/actions/index.js
package.json