React 应用框架在蚂蚁金服的实践

陈成 (花名:云谦)

Dva

蚂蚁金服

杭州

此次分享包含:

  • 蚂蚁金服前端应用架构历程
  • 介绍 Dva,基于 redux 的前端框架
  • 我们的前端技术栈

Let's
Get
Started!

PlainReact

Roof

Roof@0.5

Redux

Dva

应用架构历程

Roof 0.4

  • 第一个版本的应用架构
  • 类似 baobab

Roof 0.5

Redux

  • 轻量级数据流方案,解决从 state 到 component 的单向数据流转问题 
  • 借助 Action 和 Reducer 实现可预测的 state 变更
  • 社区活跃,丰富的扩展、调试方案
  • ...

Redux 最佳实践

新的问题

  • 非常多的库供选择
  • 代码写哪里?是个问题
  • 代码分散,影响专注力
  • 一遍遍重复地写 showLoadinghideLoading
  • 出错处理太繁琐,每个异步 saga 都要 try .. catch
    
  • 项目太大了,我需要动态加载方案
  • ...

Dva

Build redux application easier and better.

Dva @ 蚂蚁金服

Dva 是什么

  • 框架,而非类库

  • 基于 redux, react-router, redux-saga 的轻量级封装

  • 借鉴 elm 的概念,Reducer, Effect 和 Subscription

  • ...

特性

  • 仅有 5 个 API

  • 支持 HMR

  • 支持 SSR (ServerSideRender)

  • 支持 Mobile/ReactNative

  • 支持 TypeScript

  • 支持路由和 Model 的动态加载

  • 完善的语法分析库 dva-ast

  • ...

初印象

import dva from'dva';

// 1. 创建 dva 实例
const app = dva();

// 2. 装载插件 (可选)
app.use(require('dva‐loading')());

// 3. 注册 Model
app.model(require('./models/count'));

// 4. 配置路由
app.router(require('./router'));

// 5. 启动应用
app.start('#root');

DEMO

5 个 API

  • app = dva(Opts)

  • app.use(Hooks)

  • app.model(ModelObject)

  • app.router(Function)

  • app.start([HTMLElement], opts)

8 个概念

  • State

  • Action

  • Model

    • Reducer

    • Effect

    • Subscription

  • Router

    • RouteComponent

State

  • State 表示应用的数据层,由 model 的 state 组成全局的 state

{
  todos:[],
  visibilityFilter:'SHOW_ALL',
}

全局 State

app.model({namespace:'todos', state: []});
app.model({namespace:'visibilityFilter', state: 'SHOW_ALL'});

Model

Action

  • Action 表示操作事件,可以是同步,也可以是异步

{
  type: String,
  payload: Any?,
  error? Error,
}

格式

dispatch(Action);
dispatch({ type: 'todos/add', payload: 'Learn Dva' });

触发 action

Model

  • Model 非 MVC 中的 M,而是领域模型,用于把数据相关的逻辑聚合到一起

  • 包含 5 个 key

    • namespace

    • state

    • reducers

    • effects

    • subscriptions

Model 例子

export default {
  namespace: 'todos',
  state: [],

  reducers: {
    // 保存 todos
    save(state, { payload }) {
      return payload;
    },

    // 添加 todo
    add(state, { payload }) {
      return [...state, payload];
    },
  },

  effects: {
    // 异步获取 todos,然后通过 action 保存
    *fetch(action, { call, put }) {
      const todos = yield call(service.fetchTodos);
      yield put({ type: 'save', payload: todos });
    },
  },
}

Reducer

  • Reducer 是唯一可以修改 state 的地方,接收 state 和 action,返回新的 state 。

(state, action) => newState

格式

// good
function(state, action) {
  return state + action.payload;
}

// bad
const foo = 1;
function(state, action) {
  return state + action.payload + foo;
}

例子

Effect

  • Effect 用于处理异步逻辑,基于 redux-saga 实现
  • 基于 Generator
*(action, effects) => void

格式

*fetch(action, { call, put, select }) {
  const todos = yield call(fetchTodos);
  yield put({ type: 'save', payload: todos });
},

例子

Subscription

  • Subscription 表示订阅,用于订阅一个数据源,然后按需 dispatch action。
({ history, dispatch }) => Function|void

格式

function({ dispatch, history }) {
  history.listen(({ pathname }) => {
    if (pathname === '/users') {
      dispatch({
        type: 'users/fetch',
      });
    }
  });
},

例子

Router

  • Router 表示路由配置信息

({ history, app }) => JSXElement | Object

格式

export default function({ history }){
  return(
    <Router history={history}>
      <Route path="/" component={App} />
    </Router>
  );
}

例子

RouteComponent

  • RouteComponent 表示 Router 里匹配路径的 Component,通常会绑定 model 的数据

import { connect } from 'dva';

function App() {
  return <div>App</div>;
}

function mapStateToProps(state) {
  return { todos: state.todos };
}

export default connect(mapStateToProps)(App);

例子

整体架构

dva 生态

蚂蚁金服前端技术栈

相关资源

Thank you!

dva

By sorrycc

dva

dva: react application arch in ant financial

  • 80,832