008 dva.js框架

8/5/2021 Javascript

经过一段时间的学习,我们已经能理解redux的概念,也能熟练使用中间件进行异步操作等,这种数据流控制可以让应用更可控也让逻辑更加清晰。

但是带来的问题是:

  1. 编辑成本高,需要在 reducer, saga, action 之间来回切换

    redux 的项目通常要分 reducer, action, saga, component 等等,我们需要在这些文件之间来回切换。并且这些文件通常是分目录存放的:

    + src
      + sagas
        - user.js
      + reducers
        - user.js
      + actions
        - user.js
    
    1
    2
    3
    4
    5
    6
    7

    所以通常我们需要在这三个 user.js 中来回切换

  2. 不便于组织业务模型 (或者叫 domain model) 。比如我们写了一个 userlist 之后,要写一个 productlist,需要复制很多文件。

  3. saga 书写太复杂,每监听一个 action 都需要走 fork -> watcher -> worker 的流程

    function *userCreate() {
      try {
        // Your logic here
      } catch(e) {}
    }
    function *userCreateWatcher() {
      takeEvery('user/create', userCreate);
    }
    function *rootSaga() {
      yield fork(userCreateWatcher);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    对于 redux-saga 来说,这样设计可以让实现更灵活,但对于我们的项目而言,大部分场景只需要用到 takeEverytakeLatest 就足够,每个 action 的监听都需要这么写就显得非常冗余

  4. entry 书写麻烦

    除了 redux store 的创建,中间件的配置,路由的初始化,Providerstore 的绑定,saga 的初始化,还要处理 reducer, component, saga 的 HMR 。这就是真实的项目应用 redux 的例子,看起来比较复杂

基于以上原因支付宝团队封装了 dva 框架

import React from 'react';
import dva, { connect } from 'dva';
import { Route } from 'dva/router';

// 1. Initialize
const app = dva();

// 2. Model
app.model({
  namespace: 'count',
  state: 0,
  reducers: {
    ['count/add'  ](count) { return count + 1 },
    ['count/minus'](count) { return count - 1 },
  },
});

// 3. View
const App = connect(({ count }) => ({
  count
}))(function(props) {
  return (
    <div>
      <h2>{ props.count }</h2>
      <button key="add" onClick={() => { props.dispatch({type: 'count/add'})}}>+</button>
      <button key="minus" onClick={() => { props.dispatch({type: 'count/minus'})}}>-</button>
    </div>
  );
});

// 4. Router
app.router(
  <Route path="/" component={App} />
);

// 5. Start
app.start(document.getElementById('root'));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

5 步 4 个接口完成单页应用的编码,不需要配 middleware,不需要初始化 saga runner,不需要 fork, watch saga,不需要创建 store,不需要写 createStore,然后和 Provider 绑定,等等。但却能拥有 redux + redux-saga + ... 的所有功能。


参考:

支付宝前端应用架构的发展和选择 (opens new window)

dva介绍 (opens new window)

React+Redux 最佳实践 (opens new window)

Last Updated: 8/7/2021, 11:10:08 PM