如何在 React Hooks 項目中進行狀態管理?

1. 選手入場

一提起 React 狀態管理,不少人就提也不想提。html

Redux: 1 號選手,人氣最高的一個,得與 react-redux 一同使用。本身無論異步,因此常聽到的什麼 redux-thunkredux-saga 是其下屬,專門擦屁股的。特色就是難用,若是按照官方文檔的寫法用,基本就是想死。推薦閱讀:www.zhihu.com/question/33…vue

Mobx: 2 號選手,使用監聽的方式,與 React 的思想背道而馳,思想有問題,流氓!react

dva: Redux 封裝,使用了 redux-saga,generator 的寫法,想死。git

Rematch: Redux 封裝,相似 dva,model 中分爲 reducerseffects,不夠簡潔。github

廣告:因此仍是 🐤 Retalk 最簡單,史上最簡單的 Redux 封裝,走過路過不要錯過:github.com/nanxiaobei/…vuex

2. React Hooks 來了

無論怎麼說,Hooks 來了,之前的狀態管理都是給之前的開發方式用的,爲了對 Hooks 有點表示,也就加幾個 useBlabla() 完事。redux

與 Hooks 的輕靈相比,它們都顯得笨重、老態龍鍾、敷衍。bash

有沒有專用於 Hooks 的狀態管理呢?目前尚未衆望所歸的,基本都是老選手搞個兼職,有點不三不四。服務器

不夠革命。異步

3. 咱們爲何須要狀態管理?

一個是爲了解決相鄰組件的通訊問題。

雖然能夠經過「狀態提高」解決,但有兩個問題:

  1. 每次子組件更新,都會觸發負責下發狀態的父組件的總體更新(使用 Context 也有這個問題),而後寫一大堆 PureComponentshouldComponentUpdate,代碼還能看嗎?React 設計中的糟粕寫了個夠,太慘。

  2. 邏輯比較多的話,都寫在父組件裏,代碼還能看嗎?根本不考慮父組件的感覺。

因此「狀態提高」不是個好思路,仍是須要狀態管理。

另外,狀態管理最重要的一個好處,就是 ——

它能夠把「與服務器交互」和「操做數據」的邏輯,從組件中提取出去,組件只用接收處理好的數據便可。這就至關於分離了個 Service 層出去,很好的開發模式。

代碼邏輯分離,各司其職,組件去幹組件該乾的事,這纔是最大的好處。

因此咱們須要狀態管理。

4. 咱們須要什麼樣的狀態管理?

若是一開始是從 Redux 上手,會發現它提供了一個全局的 store。而後呢?而後它也沒說什麼話,有什麼問題就本身解決吧,我先睡了。

實際業務開發中,遇到的最多見的場景,就是須要區分不一樣的「模塊」,這是最基本的需求。

Vuex 比較務實,提供了 modules 的概念。

Redux 呢?固然是得靠你本身啦,咱們提供一個理念就好了,這麼簡單的東西,你就本身去搞吧。

若是不從 API 設計上進行規範,必然會致使無數不一樣的實現。(單押 x 2)

CHAOS.

咱們須要什麼樣的狀態管理?

咱們須要符合中國特點社會主義初級階段國情的狀態管理。

咱們須要能夠劃分不一樣的模塊,模塊是獨立的,同時模塊間又是能夠自由溝通的。

不少狀態管理庫只考慮了模塊的「獨立」,可是對「溝通」保持沉默,這是不友好的。

獨立,且連通 —— 這纔是模塊的意義所在。

5. 模塊如何劃分?

通常來講,推薦按照基本的路由入口,劃分出不一樣的模塊,這也是 dva 中的思路(它的文件夾乾脆就叫 routes)。

這也符合天然的思惟方式,劃分路由,也就是自然的認爲它們屬於不一樣的模塊。

而每一個狀態管理的模塊,咱們稱之爲 "model",建議與路由入口組件綁定起來,每一個入口組件及其子組件,總體對應一個 model。

---A
    index.jsx
    model.js
---B
    index.jsx
    model.js
---C
    index.jsx
    model.js
複製代碼

6. 模塊如何溝通?

模塊是獨立的,毋庸置疑,模塊模塊,不獨立還叫模塊嗎?

那模塊如何溝通呢?

在組件中,能夠獲取到自身 model 和其它的 model,這並不難。

主要是,在 model 內部,自身各個方法須要互相調用,同時須要拿到其它 model 的數據和方法,這纔是溝通的意義。

還得足夠簡單。

這樣纔是一個良好而完全的設計。

7. Hooks 組件中如何獲取 model?

最直接的,咱們但願在組件中,經過 Hooks 去訪問到某個 model。

const { someStateInA, someActionInA } = useModel(a);
// or
const { someStateInA, someActionInA, someStateInB, someActionInB } = useModels(a, b);
複製代碼

useModel() 中傳入某個 model,這樣設計的話,須要哪一個 model,就得在組件中引入 model 的文件,不夠自由,不能依賴於必須去引入文件。

只要操做麻煩,代碼寫的變多,就不是好的設計。

另外 Hooks 是爲了讓代碼更清晰,咱們不能像 Mobx 同樣,違背總體系統的設計哲學。

因此 model 獲取最好是分開的,useModels(a, b) 一次性引入多個 model 的方式,不夠清晰。

不能依賴文件,引入得清晰,因此:

const { someStateInA, someActionInA } = useModel('a');
const { someStateInB, someActionInB } = useModel('b');
複製代碼

依賴一個字符串,這樣就不須要在每一個組件中引入文件。useModel() 只能訪問一個 model,代碼足夠清晰。

這是咱們須要的設計。

8. model 結構如何設計?

一個 model 整體來講能夠分爲兩大塊,數據(state)和操做數據的方法(reducerseffects)。

reducerseffects,或者 Vuex 中的 mutationsactions,是爲了區分直接改變和異步操做,同步函數和異步函數。不夠簡潔,能不能合併成一個?

答案能夠的,咱們稱之爲 actions

更新 state 的方法,直接注入 model 中,因此一個 action 能夠是同步也能夠是異步,它只是被當作函數來調用。

因而,model 中分爲兩塊就好:

exports default {
    state: {},
    actions: {},
}
複製代碼

9. model 溝通如何設計?

model 溝通,主要是實如今 action 中去訪問其它須要的東西。

自由而無限制的溝通。

一個 action 中須要訪問到如下:1. 自身 state,2. 自身 action,3. 其它模塊 state,4. 其它模塊 action,5. 自身 state updater。

簡化一下,就是須要訪問:1. 自身 model,2. 其它 model,3. 自身 state updater。

再簡化一下:1. model,2. 自身 state updater。

因此其實只須要兩個方法:getModel()setState()

getModel() 獲取自身,getModel('other') 獲取其它。

如何拿到這兩個方法呢?

  1. 經過 this 訪問。但咱們是給 Hooks 設計狀態管理,Hooks 就是爲了拋棄 this,仍是那句話 —— 不能違背系統的設計哲學

  2. Vuex 中,是在函數第一個參數注入 context,調用時比較反直覺,放棄這種方式。

  3. model 文件中 import 方法進來,太麻煩了,只要操做麻煩,代碼寫的變多,就不是好的設計

因此惟一的方式(Rematch 的設計中也能看到),就是在參數中注入方法。

也就是把 actions 變爲一個函數:

exports default {
    state: {},
    actions: ({ getModel, setState }) => ({
        someAction() {
            const { someState, someOtherAction } = getModel();
        }
    }),
}
複製代碼

這裏考慮到一個美學問題,getModel() 由於不少 action 都會用到,而實際寫出來時,由於 l 高度的問題,又比較醜,因此就把 API 簡化爲了 model()

model() 獲取自身,model('other') 獲取其它。

10. flooks 是什麼?

因而,flooks,福祿克斯,誕生了:


🍸 flooksgithub.com/nanxiaobei/…


import { setModel, useModel } from 'flooks';

const a = {
    state: {},
    actions: ({ model, setState }) => ({
        someAction() {
            const { someState, someOtherAction } = model();
            ...
            setState(payload);
        }
    }),
}

setModel('a', a);

function A() {
    cosnt { someState, someAction } = useModel('a');
    return (
        ...
    )
}
複製代碼

自然的模塊化支持。

只有兩個 API,setModel()useModel()

加上 actions 的兩個參數,model()setState(),就這麼多。

足夠簡單,足夠實現一切。

One more thing. 設計哲學

去中心化,去中心化,去中心化。

一切都爲了更簡單的開發。

再不須要頂層分發 store,不須要 store 文件夾或 store.js 文件。

無需頂層 createStore(),無需頂層 Provider

註冊 model 時,無需先在中心化文件中引入 model,自身文件夾內就能夠搞定一切。

直接用 setModel() 把組件和 model 鏈接起來,就這麼簡單。

模塊化,積木同樣組合,簡潔,靈活,這是咱們的理念。

每一個組件和 model 構成一個自組織,同時它們又能夠訪問到世界各地。它們不用去有關部門報道,就能在世界的任何角落相遇。

這是咱們的哲學:獨立,自由,個體,世界。

相關文章
相關標籤/搜索