dva API
app = dva(opts)
创建应用,返回 dva 实例。(注:dva 支持多实例)
opts
包含:
history
:指定给路由用的 history,默认是hashHistory
initialState
:指定初始数据,优先级高于 model 中的 state,默认是{}
如果要配置 history 为browserHistory
,可以这样:
import createHistory from 'history/createBrowserHistory';
const app = dva({
history: createHistory(),
});
另外,出于易用性的考虑,opts
里也可以配所有的 hooks ,下面包含全部的可配属性:
const app = dva({
history,
initialState,
onError,
onAction,
onStateChange,
onReducer,
onEffect,
onHmr,
extraReducers,
extraEnhancers,
});
app.use(hooks)
配置 hooks 或者注册插件。(插件最终返回的是 hooks )
比如注册 dva-loading 插件的例子:
import createLoading from 'dva-loading';
...
app.use(createLoading(opts));
hooks
包含:
onError((err, dispatch) => {})
effect
执行错误或 subscription
通过 done
主动抛错时触发,可用于管理全局出错状态。
注意:subscription
并没有加 try…catch
,所以有错误时需通过第二个参数 done
主动抛错。例子:
app.model({
subscriptions: {
setup({ dispatch }, done) {
done(e);
},
},
});
如果我们用 antd,那么最简单的全局错误处理通常会这么做:
import { message } from 'antd';
const app = dva({
onError(e) {
message.error(e.message, /* duration */3);
},
});
onAction(fn | fn[])
在 action 被 dispatch 时触发,用于注册 redux 中间件。支持函数或函数数组格式。
例如我们要通过 redux-logger 打印日志:
import createLogger from 'redux-logger';
const app = dva({
onAction: createLogger(opts),
});
onStateChange(fn)
state
改变时触发,可用于同步 state
到 localStorage,服务器端等。
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 };
},
},
});
onEffect(fn)
封装 effect 执行。比如 dva-loading 基于此实现了自动处理 loading 状态。
onHmr(fn)
热替换相关,目前用于 babel-plugin-dva-hmr 。
extraReducers
指定额外的 reducer,比如 redux-form 需要指定额外的 form
reducer:
import { reducer as formReducer } from 'redux-form'
const app = dva({
extraReducers: {
form: formReducer,
},
});
extraEnhancers
指定额外的 StoreEnhancer ,比如结合 redux-persist 的使用:
import { persistStore, autoRehydrate } from 'redux-persist';
const app = dva({
extraEnhancers: [autoRehydrate()],
});
persistStore(app._store);
app.model(model)
注册 model,详见 #Model 部分。
app.unmodel(namespace)
取消 model 注册,清理 reducers, effects 和 subscriptions。subscription 如果没有返回 unlisten 函数,使用 app.unmodel
会给予警告⚠️。
app.replaceModel(model)
只在app.start()之后可用
替换model为新model,清理旧model的reducers, effects 和 subscriptions,但会保留旧的state状态,对于HMR非常有用。subscription 如果没有返回 unlisten 函数,使用 app.unmodel
会给予警告⚠️。
如果原来不存在相同namespace的model,那么执行app.model
操作
app.router(({ history, app }) => RouterConfig)
注册路由表。
通常是这样的:
import { Router, Route } from 'dva/router';
app.router(({ history }) => {
return (
<Router history={history}>
<Route path="/" component={App} />
</Router>
);
});
推荐把路由信息抽成一个单独的文件,这样结合 babel-plugin-dva-hmr 可实现路由和组件的热加载,比如:
app.router(require('./router'));
而有些场景可能不使用路由,比如多页应用,所以也可以传入返回 JSX 元素的函数。比如:
app.router(() => <App />);
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(<IntlProvider><App /></IntlProvider>, htmlElement);