redux和mobx比較(二)

Redux

Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。react

redux

三大核心

在 Redux 中,最爲核心的概念就是 action 、reducer、store 以及 state,那麼具體是什麼呢?編程

  • Action:是把數據從應用傳到 store 的有效載荷。它是 store 數據的惟一來源
  • Reducer:指明如何更新 state
  • Store:把 action、Reducer 聯繫到一塊兒的對象,負責維持、獲取和更新state

數據流

嚴格的單向數據流是 Redux 架構的設計核心。json

Redux 應用中數據的生命週期遵循下面 4 個步驟:redux

  • 調用 store.dispatch(action) 觸發 action
  • Redux store 調用傳入的 reducer 函數
  • 根 reducer 應該把多個子 reducer 輸出合併成一個單一的 state 樹
  • Redux store 保存了根 reducer 返回的完整 state 樹

搭配 React

react-redux

核心庫:數組

1
2
3
4
5
6
7
react
react-dom
react-router
react-router-redux //利用react-router-redux提供的syncHistoryWithStore咱們能夠結合store同步導航事件
redux
react-redux
react-thunk/react-saga/redux-logger //middleware

 

目錄結構:promise

1
2
3
4
5
6
7
8
9
10
├─app
│ ├─actions //redux動做生成器
│ ├─assets //靜態資源
│ ├─compontens //UI組建
│ ├─containers //容器組件
│ ├─reducers
│ ├─routes
│ ├─store
│ └─utils //工具函數
└─dist //發佈目錄

 

不過使用過 Redux 的人會有這些痛點:難懂的 API、複雜的邏輯、過多的代碼侵入。Redux 採用單一根節點、函數式編程、動做分離管理(彷佛讓項目很容易管理),這些都是 Redux 過於複雜的緣由。然這裏並非說 Redux 很差。基於項目自己,尋找一個最適合的框架纔是優的解決方案。網絡

Mobx

MobX 是一個通過戰火洗禮的庫,它經過透明的函數響應式編程(transparently applying functional reactive programming - TFRP)使得狀態管理變得簡單和可擴展。數據結構

比起Redux,Mobx基於觀察者模式,採用多節點管理數據,是一個很輕量、入手簡單、代碼耦合小的數據框架。react-router

核心概念

數據流

MobX 爲單向數據流,也就是動做改變狀態,而狀態的改變會更新全部受影響的視圖。架構

mobx-fow

它由幾個部分組成:Actions、State、Computed Values、Reactions。使用 MobX 將一個應用變成響應式的可概括爲如下步驟:

  • 經過事件驅動(UI 事件、網絡請求…)觸發 Actions
  • 在 Actions 中修改了 State 中的值,這裏的 State 既應用中的 store 樹(存儲數據)
  • 而後根據新的 State 中的數據計算出所須要的計算屬性(computed values)值
  • 響應(react)到 UI 視圖層

Observable state(可被觀察的狀態)

MobX 爲現有的數據結構(如對象,數組和類實例)添加了可觀察的功能。 經過使用 @observable 裝飾器來給你的類屬性添加註解就能夠簡單地完成這一切。這樣改屬性就變成了「被觀察者」。

1
2
3
class Store {
@observable a = 'Hello Word!';
}

Observer(觀察者)

observer 函數裝飾器能夠用來將 React 組件轉變成響應式組件。 它用 mobx.autorun 包裝了組件的 render函數以確保任何組件渲染中使用的數據變化時均可以強制刷新組件。 observer 是由單獨的 mobx-react 包提供的。

1
2
3
4
5
6
7
8
9
10
@observer
class Index extends Component {
render() {
return (
<p>
{this.props.Store.a}
</p>
)
}
}

這樣 Index 組件就變成了一個響應式的組件(智能組件),當「被觀察者」改變時,該組件就會自動更新。

componentWillReact (生命週期鉤子)

React 組件一般在新的堆棧上渲染,這使得一般很難弄清楚是什麼致使組件的從新渲染。 當使用 mobx-react 時能夠定義一個新的生命週期鉤子函數 componentWillReact。當組件由於它觀察的數據發生了改變,它會安排從新渲染,這個時候 componentWillReact 會被觸發。這使得它很容易追溯渲染並找到致使渲染的操做(action)。

inject(注入)

inject 函數裝飾器能夠將 Store 數據注入到組件當中。inject 是由單獨的 mobx-react 包提供的。

1
@inject("store")

 

Computed values(計算值)

使用 MobX,能夠定義在相關數據發生變化時自動更新的值。 經過 @computed 裝飾器調用 的getter / setter 函數來進行使用。

1
2
3
4
5
6
7
class ItemsStore {
@observable items = [];

@computed get total() {
return this.items.length;
}
}

當添加了一個新的 items 時,MobX 會確保 total 自動更新。

Action(動做)

action 是任一一段能夠改變狀態的代碼。具體實現代碼以下:

1
2
3
4
5
6
7
8
9
10
class HomeStore {
@observable num = 0;

@action plus = () => {
this.num = ++this.num
}
@action minus = () => {
this.num = --this.num
}
}

若是是在嚴格模式:

1
2
import { useStrict } from 'mobx';
useStrict(true);

那麼 MobX 會強制只有在動做之中才能夠修改狀態。對於任何不使用動做的狀態修改,MobX 都會拋出異常。

異步 Action

action 包裝/裝飾器只會影響當前運行的函數,而不會影響當前函數調度(但不是調用)的函數! 這意味着若是你有一個 setTimeout、promise 的 then 或 async 語句,而且在回調函數中某些狀態改變了,這些回調函數也應該包裝在 action 中。可使用 action 關鍵字來包裝 promises 回調函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@action
fetchData = (url) => {
fetch(url).then(
action('fetchRes', res => {
return res.json()
})).then(
action('fetchSuccess', data => {
// TODO

})).catch(
action('fetchError', e => {
// err
}))
}

異步 action 實現的方式還有多種,這裏只列舉了 action 關鍵子的模式

在 React 中使用 Mobx

在 React 中使用 MobX 須要用到 mobx-react。
其提供了 Provider 組件用來包裹最外層組件節點,而且傳入 store 傳遞給後代組件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react';
import ReactDOM from 'react-dom';
import {useStrict} from 'mobx';
import {HashRouter as Router} from 'react-router-dom'
import {Provider} from 'mobx-react';
import * as stores from './store';

import App from './compontens/App'

useStrict(true) // 不容許在動做以外進行狀態修改

ReactDOM.render(
<Provider store={stores}>
<Router>
<App/>
</Router>
</Provider>, document.getElementById('root')
);

使用 @inject 給組件注入其須要的 store(利用 React context 機制);
經過 @observer 將 React 組件轉化成響應式組件,它用 mobx.autorun 包裝了組件的 render 函數以確保任何組件渲染中使用的數據變化時均可以強制刷新組件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, {Component} from 'react'
import {observer, inject} from 'mobx-react'
import {withRouter} from 'react-router-dom'

@withRouter @inject('store') @observer
class App extends Component {

render() {
return (
<div className="main">
//……
</div>
)
}
}

export default App

其中 @withRouter 是 router 的 參數傳入到組件中。

相關文章
相關標籤/搜索