本文旨在用盡量通俗易懂的方式講清楚 hox 在底層是如何實現的,也所以可能在某些方面的表述不夠嚴謹,若有偏頗,還請各位讀者多多指正。
Hox 是下一代的 React 狀態管理器,關於它的更多介紹能夠參考這篇文章,本文假設你已經對 hox 的用法有了初步的瞭解。git
在 hox 中,咱們但願能充分發揮 React Hooks 的特性,也但願讓全局狀態和組件內部狀態的編寫體驗保持一致,因此咱們使用 custom Hook 的方式定義 model 的邏輯。github
咱們不妨先來看下一個普通的 custom Hook 是什麼樣的效果吧:segmentfault
export function useFoo() { const [count, setCount] = useState(0) function increment() { setCount(count + 1) } return { count, increment, } }
咱們能夠在組件中調用 useFoo
:app
export function ComponentA() { const foo = useFoo() return ( <div> <p>{foo.count}</p> <button onClick={foo.increment}>Increment</button> </div> ) }
不難發現,咱們經過定義 custom Hook ,對邏輯進行了一層封裝,也讓組件變得更加簡潔。然而,若是此時咱們再建立一個 B 組件:spa
export function ComponentB() { const foo = useFoo() return ( <div> <p>{foo.count}</p> </div> ) }
當咱們點擊 A 組件中的 Increment 按鈕時,B 組件中的數字會跟着變化麼?
答案天然是不會的,由於 useFoo
這個 custom Hook 雖然實現了邏輯的封裝和複用,可是卻並不能讓數據共享。code
而 hox ,就是爲了解決這個問題而生。cdn
咱們不妨接着上面的例子,使用 hox 提供的 createModel
對 useFoo
進行一層封裝:blog
const useFooModel = createModel(useFoo)
createModel
會建立一個 Executor
組件的實例,並在其中執行 useFoo
這個 Hook ,並把 useFoo
的執行結果保存起來。最後,它會返回一個新的 Hook: useFooModel
。乍一看, createModel
和 HOC (高階組件)甚至有幾分神似。jsx
不一樣於 useFoo
,在調用 useFooModel
時,咱們並非真的執行了 useFoo
這個 custom Hook ,而是向 Executor
組件進行數據的訂閱。也就是說,若是咱們在多個組件中都調用了 useFooModel
,那它們所拿到的數據其實是同一份,更準確的說,它們拿到的那份數據,就是存在 Executor
中的那份 state
。rem
經過這種方式,咱們讓 custom Hook 能夠作到數據的共享,這也是 createModel
之因此叫作 createModel
的緣由:經過它,咱們把一個 custom Hook 變成了一個全局的 model 。
如今,咱們再來更新一下剛纔的例子:
export function ComponentA() { const foo = useFooModel() // 這裏從 useFoo 變成了 useFooModel return ( <div> <p>{foo.count}</p> <button onClick={foo.increment}>Increment</button> </div> ) } export function ComponentB() { const foo = useFooModel() // 這裏從 useFoo 變成了 useFooModel return ( <div> <p>{foo.count}</p> </div> ) }
如今,A B 兩個組件都獲取到了 Executor
中的那份數據,而且訂閱了它將來的更新。所以當咱們點擊組件 A 的 Increment 按鈕時,咱們其實是觸發了 Executor
組件中的一個 setState
,而後 Executor
組件進行重渲染,通知它的訂閱者們。A 組件和 B 組件收到了更新通知和新的數據,也會跟着從新進行渲染。最終咱們能夠看到,A B 兩個組件顯示的數字都變成了 1
。