Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux 和 Mobx 哪个更适合你? #23

Open
Hancoson opened this issue Dec 26, 2017 · 0 comments
Open

Redux 和 Mobx 哪个更适合你? #23

Hancoson opened this issue Dec 26, 2017 · 0 comments

Comments

@Hancoson
Copy link
Owner

Hancoson commented Dec 26, 2017

Redux is a predictable state container for JavaScript apps. —— Redux
Simple, scalable state management. —— Mobx

从 Redux 和 Mobx 官方的介绍很容易可以看出,它们都是用来管理应用的 state。但是它们有什么区别呢?刚好最近把之前使用 Reudx 做的 React 项目使用 Mobx 重构了,那么就来总结一下吧。

Redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

redux

三大核心

在 Redux 中,最为核心的概念就是 action 、reducer、store 以及 state,那么具体是什么呢?

  • Action:是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源
  • Reducer:指明如何更新 state
  • Store:把 action、Reducer 联系到一起的对象,负责维持、获取和更新state

数据�流

严格的单向数据流是 Redux 架构的设计核心。

Redux 应用中数据的生命周期遵循下面 4 个步骤:

  • 调用 store.dispatch(action) 触发 action
  • Redux store 调用传入的 reducer 函数
  • 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树
  • Redux store 保存了根 reducer 返回的完整 state 树

搭配 React

react-redux

核心库:

react
react-dom
react-router
react-router-redux  //利用react-router-redux提供的syncHistoryWithStore我们可以结合store同步导航事件
redux
react-redux
react-thunk/react-saga/redux-logger  //middleware

目录结构:

├─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基于观察者模式,采用多节点管理数据,是一个很轻量、入手简单、代码耦合小的数据框架。

核心概念

数据流

MobX 为单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图。

mobx-fow

它由几个部分组成:Actions、State、Computed Values、Reactions。使用 MobX 将一个应用变成响应式的可归纳为以下步骤:

  • 通过事件驱动(UI 事件、网络请求…)触发 Actions
  • 在 Actions 中修改了 State 中的值,这里的 State 既应用中的 store 树(存储数据)
  • 然后根据新的 State 中的数据计算出所需要的计算属性(computed values)值
  • 响应(react)到 UI 视图层

Observable state(可被观察的状态)

MobX 为现有的数据结构(如对象,数组和类实例)添加了可观察的功能。 通过使用 @observable 装饰器来给你的类属性添加注解就可以简单地完成这一切。这样改属性就变成了“被观察者”。

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

Observer(观察者)

observer 函数装饰器可以用来将 React 组件转变成响应式组件。 它用 mobx.autorun 包装了组件的 render 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件。 observer 是由单独的 mobx-react 包提供的。

@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 包提供的。

@inject("store")

Computed values(计算值)

使用 MobX,可以定义在相关数据发生变化时自动更新的值。 通过 @computed 装饰器调用 的getter / setter 函数来进行使用。

class ItemsStore {
  @observable items = [];

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

当添加了一个新的 items 时,MobX 会确保 total 自动更新。

Action(动作)

action 是任一一段可以改变状态的代码。具体实现代码如下:

class HomeStore {
  @observable num = 0;

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

如果是在严格模式:

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

那么 MobX 会强制只有在动作之中才可以修改状态。对于任何不使用动作的状态修改,MobX 都会抛出异常。

异步 Action

action 包装/装饰器只会影响当前运行的函数,而不会影响当前函数调度(但不是调用)的函数! 这意味着如果你有一个 setTimeout、promise 的 then 或 async 语句,并且在回调函数中某些状态改变了,这些回调函数也应该包装在 action 中。可以使用 action 关键字来包装 promises 回调函数

@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 传递给后代组件:

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 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件:

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 的 参数传入到组件中。

结束语

说到这里就会有人问,那到底哪种框架好呢?这个问题我也不知道�怎么回答是对的,各有各的优点(谁用谁知道)。

很明显 Mobx 的代码要精简得多。通过 OOP 风格和良好的开发实践,你可以快速的构建各种应用。最大的弊病是很容易编写糟糕的不可维护的代码。但是,社区发展方面 Mobx 在国内的发展还是比较缓慢的,遇到的问题可能社区都没有遇到过。

而 Redux 更受欢迎一些,而且特别适合构建大型复杂应用。这是一个规定严格的框架,其规则确保开发人员可以编写易于测试和可维护的代码。但是,的确不适合开发小项目。

两个库都非常棒。Redux 已经非常完善,Mobx 则逐渐成为一个有效的替代。

其他

项目地址

本文中中使用的源码均以开源:

欢迎交流,欢迎 Star

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant