從 Redux 到 Mobx: 狀態管理的演化

在 Web 前端開發中,狀態管理是一個非常重要且基礎的主題。隨着前端技術的不斷髮展,狀態管理也在不斷地演化和進化。本文將介紹狀態管理庫 Redux 和 Mobx 的異同以及它們的演化軌跡。

Redux

Redux 是由 Dan Abramov 開發的一款狀態管理庫,它的核心思想是單一數據源,不可變數據和純函數更新。Redux 將應用的狀態存儲在一個 JavaScript 對象樹中,稱爲 store。通過定義 action 和 reducer 來更新 store 中保存的狀態。

Action

Action 是對狀態變化的描述。每個 action 都包含一個 type 屬性,表示它的類型。例如:

{
  type: 'ADD_TODO',
  payload: {
    text: 'Learn Redux'
  }
}

Reducer

Reducer 是純函數,它接收當前狀態和一個 action,並返回新的狀態。例如:

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.payload.text,
          completed: false
        }
      ]
    default:
      return state
  }
}

Store

Store 是 Redux 中存儲應用狀態的地方。它是唯一的,和 reducers 協作來實現狀態更新。創建 store:

import { createStore } from 'redux'
import todos from './reducers'

const store = createStore(todos)

以上就是 Redux 的基本使用方法,Redux 讓狀態管理變得簡單、可控且易於擴展。但是 Redux 的缺點也很明顯,需要寫很多的樣板代碼,使用起來有些繁瑣。

Mobx

Mobx 是一款簡單、高效、易用的狀態管理庫,它的核心思想是響應式編程。Mobx 使用了觀察者模式,當被觀察對象(observable)發生改變時,會自動通知觀察者(observer),進而引發界面的重新渲染。

Observable

Observable 可以將普通對象轉換成可觀察對象。我們只需要使用 observable 函數包裹對象即可:

import { observable } from 'mobx'

const todo = observable({
  text: 'Learn Mobx',
  completed: false
})

Computed

Computed 是計算屬性,它可以根據 observable 的值計算出新的值,並且只有在依賴的 observable 改變時纔會重新計算。例如:

import { observable, computed } from 'mobx'

const todo = observable({
  text: 'Learn Mobx',
  completed: false
})

const TodoView = observer(({ todo }) => (
  <div>
    <input
      type="checkbox"
      checked={todo.completed}
      onClick={() => { todo.completed = !todo.completed }}
    />
    <span>{todo.text}</span>
    <span>{todo.isCompleted ? '✔' : '❌'}</span>
  </div>
))

const TodoList = observer(({ todos }) => (
  <div>
    {todos.map(todo => (
      <TodoView key={todo.id} todo={todo} />
    ))}
    <p>Completed: {todos.filter(todo => todo.completed).length}/{todos.length}</p>
  </div>
))

const todos = observable([
  {
    text: 'Learn Mobx',
    completed: true
  },
  {
    text: 'Learn React',
    completed: false
  }
])

const completedCount = computed(() => todos.filter(todo => todo.completed).length)

ReactDOM.render(
  <TodoList todos={todos} completedCount={completedCount} />,
  document.getElementById('root')
)

Action

在 Mobx 中並沒有專門的 action,我們可以把修改 observable 的操作放到一個函數里面,然後在這個函數前面添加 @action 裝飾器標識這是一個 action:

import { observable, computed, action } from 'mobx'

class### Class

 Mobx 我們通常使用 class 來組織代碼類中的屬性可以使用 observable() 裝飾器進行轉換方法可以使用 action() 裝飾器來聲明爲 action

```javascript
import { observable, computed, action } from 'mobx'

class Todo {
  @observable text = ''
  @observable completed = false

  constructor(text) {
    this.text = text
  }

  @action.bound
  toggleCompleted() {
    this.completed = !this.completed
  }
}

class TodoList {
  @observable todos = []

  constructor() {
    this.todos.push(new Todo('Learn Mobx'))
    this.todos.push(new Todo('Learn React'))
  }

  @computed get completedCount() {
    return this.todos.filter(todo => todo.completed).length
  }

  @action.bound
  addTodo(text) {
    this.todos.push(new Todo(text))
  }
}

const TodoView = observer(({ todo }) => (
  <div>
    <input
      type="checkbox"
      checked={todo.completed}
      onClick={todo.toggleCompleted}
    />
    <span>{todo.text}</span>
    <span>{todo.isCompleted ? '✔' : '❌'}</span>
  </div>
))

const TodoListView = observer(({ todoList }) => (
  <div>
    <button onClick={() => { todoList.addTodo('New Todo') }}>Add Todo</button>
    {todoList.todos.map(todo => (
      <TodoView key={todo.id} todo={todo} />
    ))}
    <p>Completed: {todoList.completedCount}/{todoList.todos.length}</p>
  </div>
))

const todoList = new TodoList()

ReactDOM.render(
  <TodoListView todoList={todoList} />,
  document.getElementById('root')
)


<p data-line="200" class="sync-line" style="margin:0;"></p>

Redux vs Mobx

Redux 和 Mobx 都有各自的優缺點,如下表所示:

dpBRLM

選擇使用哪種狀態管理庫需要根據具體的項目需求和團隊實際情況而定。

結語

狀態管理是 Web 前端開發中不可或缺的一個話題,在這篇文章中我們介紹了 Redux 和 Mobx 這兩款流行的狀態管理庫,並比較了它們之間的異同。希望讀者能夠通過本文學習到更深入的知識,並對狀態管理有更清晰的認識。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/39rNSmX-E0xhQxMwwDvRmg