博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
初识React(9):dva简介
阅读量:5902 次
发布时间:2019-06-19

本文共 4360 字,大约阅读时间需要 14 分钟。

前言

dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。

import dva from 'dva';// 1. Initializeconst app = dva();// 2. Pluginsapp.use({});// 3. Modelapp.model(require('./models/example').default);// 4. Routerapp.router(require('./router').default);// 5. Startapp.start('#root');

dva仅有6个api,如下介绍:

1. const app = dva(options)

创建应用,返回dva实例

options中包含:

(1) history:默认为hashHistory,如果要配置history为browserHistory,则

import createHistory from 'history/createBrowserHistory';const app = dva({  history: createHistory(),});

(2) initialState: 指定初始数据,优先级高于model中的state,默认为{}

(3) onError: 管理全局出错状态,如下:

const app = dva({  onError(e){    console.log(e);  }});

(4) onAction(fn | fn[]): 在action被dispatch时触发,用于注册redux中间件,支持函数格式或者函数数组格式,如下通过redux-logger答应日志,如:

import createLogger from 'redux-logger';const app = dva({  onAction: createLogger(opts),});

(5) onStateChange(fn): state改变时触发,可用于同步state 到 localStorage,服务器端等

(6) onReducer(fn): 封装 reducer 执行。比如借助 redux-undo 实现 redo/undo :

import undoable from 'redux-undo';const app = dva({  onReducer: reducer => {    return (state, action) => {      const undoOpts = {};      const newState = undoable(reducer, undoOpts)(state, action);      // 由于 dva 同步了 routing 数据,所以需要把这部分还原      return { ...newState, routing: newState.present.routing };    },  },});

(7) onEffect(fn): 封装 effect 执行。比如 dva-loading 基于此实现了自动处理 loading 状态。

(8) onHmr(fn): 热替换相关,目前用于 babel-plugin-dva-hmr

(9) extraReducers: 指定额外的 reducer,比如 redux-form 需要指定额外的 form reducer

import { reducer as formReducer } from 'redux-form'const app = dva({  extraReducers: {    form: formReducer,  },});

(10) extraEnhancers: 指定额外的 StoreEnhancer ,比如结合 redux-persist 的使用

import { persistStore, autoRehydrate } from 'redux-persist';const app = dva({  extraEnhancers: [autoRehydrate()],});persistStore(app._store);

2.app.use(hooks)

配置 hooks 或者注册插件。(插件最终返回的是 hooks )

比如注册 dva-loading 插件的例子:

import createLoading from 'dva-loading';...app.use(createLoading(opts));

hooks 包含2中(3)到(10)

3.app.model(model)

注册model

model 是 dva 中最重要的概念,以下是典型的例子:

app.model({  namespace: 'todo',  state: [],  reducers: {    add(state, { payload: todo }) {      // 保存数据到 state      return [...state, todo];    },  },  effects: {    *save({ payload: todo }, { put, call }) {      // 调用 saveTodoToServer,成功后触发 `add` action 保存到 state      yield call(saveTodoToServer, todo);      yield put({ type: 'add', payload: todo });    },  },  subscriptions: {    setup({ history, dispatch }) {      // 监听 history 变化,当进入 `/` 时触发 `load` action      return history.listen(({ pathname }) => {        if (pathname === '/') {          dispatch({ type: 'load' });        }      });    },  },});

model 包含 5 个属性:

namespace: model 的命名空间,同时也是他在全局 state 上的属性,只能用字符串,不支持通过 . 的方式创建多层命名空间。

state: 初始值,优先级低于传给 dva() 的 opts.initialState,如下:

const app = dva({  initialState: { count: 1 },});app.model({  namespace: 'count',  state: 0,});

此时,在 app.start() 后 state.count 为 1

reducers: 以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方。由 action 触发,格式为 (state, action) => newState 或 [(state, action) => newState, enhancer]

effects: 以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据等等。格式为

*(action, effects) => void 或 [*(action, effects) => void, { type }]。

subscriptions: 以 key/value 格式定义 subscription。subscription 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。格式为 ({ dispatch, history }, done) => unlistenFunction。注意:如果要使用 app.unmodel(),subscription 必须返回 unlisten 方法,用于取消数据订阅。

4.app.unmodel(namespace)

取消 model 注册,清理 reducers, effects 和 subscriptions。subscription 如果没有返回 unlisten 函数,使用 app.unmodel 会给予警告

5.app.router(({ history, app }) => RouterConfig)

注册路由表。通常是这样的:

import { Router, Route } from 'dva/router';app.router(({ history }) => {  return (    
);});

推荐把路由信息抽成一个单独的文件,这样结合 babel-plugin-dva-hmr 可实现路由和组件的热加载,比如:

app.router(require('./router'));

而有些场景可能不使用路由,比如多页应用,所以也可以传入返回 JSX 元素的函数。比如:

app.router(() => 
);

6.app.start(selector)

启动应用。selector 可选,如果没有 selector 参数,会返回一个返回 JSX 元素的函数。

app.start('#root');

那么什么时候不加 selector?常见场景有测试、node 端、react-native 和 i18n 国际化支持。

比如通过 react-intl 支持国际化的例子:

import { IntlProvider } from 'react-intl';...const App = app.start();ReactDOM.render(
, htmlElement);

本文参考官网:

转载地址:http://juupx.baihongyu.com/

你可能感兴趣的文章
Android Xutils 框架
查看>>
C#基础知识整理 基础知识(21) 委托(二)
查看>>
Sysbench 0.5版安装配置
查看>>
书摘—你不可不知的心理策略
查看>>
【博客话题】毕业——开始人生的艰苦历程
查看>>
Linux安装telnet
查看>>
sap scriptfom 多语言翻译
查看>>
黄聪:3分钟学会sessionStorage用法
查看>>
Entity Framework 全面教程详解(转)
查看>>
Windows上Python2.7安装Scrapy过程
查看>>
Chapter 3:Code Style in Django
查看>>
挖掘数据金矿 领军协同创新 曙光荣膺“2016大数据创新应用领袖企业”称号
查看>>
Fast通道获得Win10 Mobile Build 14977更新
查看>>
《BackTrack 5 Cookbook中文版——渗透测试实用技巧荟萃》—第3章3.6节识别操作系统...
查看>>
linux系统防火墙iptables命令规则及配置的示例
查看>>
10 个顶尖的 Linux 开源人工智能工具
查看>>
Firefox 跟踪保护技术将页面加载时间减少 44%
查看>>
java解析虾米音乐
查看>>
rails将类常量重构到数据库对应的表中之三
查看>>
mysql 多行合并函数
查看>>