React Hooks比你想象的更強大。css
如今,咱們將探索和開發一個自定義Hook來管理全局狀態 - 比Redux更容易使用的方法,而且比Context API更高效。git
若是你已經很熟悉React Hooks,那麼能夠直接跳過這部分。github
useState()npm
在Hooks以前,功能組件沒有狀態。如今,使用useState(),咱們可讓功能組件擁有狀態。編程
useState()會返回一個數組。上面數組的第一項是一個能夠訪問狀態值的變量。第二項是一個可以更新組件狀態,並且影響dom變化的函數。json
useEffect()數組
相似Component組件,使用生命週期方法來管理反作用,例如componentDidMount()。useEffect() 函數容許您在函數組件中執行反作用。dom
默認狀況下,useEffect在每次完成渲染後運行。可是,您能夠選擇僅在某些值發生更改時觸發它,並將一個數組做爲第二個可選參數傳遞。函數式編程
要得到與 componentDidMount() 相同的結果,咱們能夠發送一個空數組。空數組不會改變,useEffect只會運行一次。函數
共享states
咱們能夠看到Hooks狀態與類組件狀態徹底相同。組件的每一個實例都有本身的狀態。
爲了組件之間共享狀態,咱們將建立一個自定義Hook。
這個想法是建立一個監聽器數組,只有一個狀態對象。每當一個組件更改狀態時,全部訂閱的組件都會觸發其 setState() 函數並進行更新。
咱們能夠經過調用自定義Hook中的 useState() 來實現。咱們將 setState() 函數添加到一個監聽器數組,並返回一個函數用來更新state 和 運行全部監聽器函數。
如今已經有了 use-global-hook 這個npm包,您能夠經過包文檔中的示例瞭解如何使用它。可是,從如今開始,咱們將專一於它是怎麼實現的。
在組件中使用它:
第一個版本已經能夠共享狀態。您能夠在應用程序中添加任意數量的Counter組件,它們都具備相同的全局狀態。
我想在第一個版本中改進的內容:
在組件卸載以前調用一個函數
咱們瞭解到,使用空數組調用 useEffect(function,[])與componentDidMount() 具備相同的用途。可是,若是第一個參數中使用的函數返回另外一個函數,則第二個函數將在卸載組件以前觸發。徹底像 componentWillUnmount()。
這是從監聽器數組中刪除組件的理想位置。
除了最後的修改,咱們還將:
由於咱們如今有一個更通用的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