Default export file.
Export the api of [email protected], and also export react-router-redux with the routerRedux
key.
e.g.
import { Router, Route, routerRedux } from 'dva/router';
Async request library, export the api of isomorphic-fetch. It's just for convenience, you can choose other libraries for free.
Export the api of redux-saga.
Util method to load React Component and dva model dynamically.
e.g.
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/UserPage'),
});
opts
include:
- app: dva instance
- models: function which return promise, and the promise return dva model
- component:function which return promise, and the promise return React Component
Create app, and return dva instance. (Notice: dva support multiple instances.)
opts
includes:
history
: Specify the history for router, defaulthashHistory
initialState
: Specify the initial state, default{}
, it's priority is higher then model state
e.g. use browserHistory
:
import createHistory from 'history/createBrowserHistory';
const app = dva({
history: createHistory(),
});
Besides, for convenience, we can configure hooks in opts
, like this:
const app = dva({
history,
initialState,
onError,
onAction,
onStateChange,
onReducer,
onEffect,
onHmr,
extraReducers,
extraEnhancers,
});
Specify hooks or register plugin. (Plugin return hooks finally.)
e.g. register dva-loading plugin:
import createLoading from 'dva-loading';
...
app.use(createLoading(opts));
hooks
includes:
Triggered when effect
has error or subscription
throw error with done
. Used for managing global error.
Notice: subscription
's error must be throw with the send argument done
. e.g.
app.model({
subscriptions: {
setup({ dispatch }, done) {
done(e);
},
},
});
If we are using antd, the most simple error handle would be like this:
import { message } from 'antd';
const app = dva({
onError(e) {
message.error(e.message, /* duration */3);
},
});
Triggered when action is dispatched. Used for register redux middleware.
e.g. use redux-logger to log actions:
import createLogger from 'redux-logger';
const app = dva({
onAction: createLogger(opts),
});
Triggered when state
changes. Used for sync state
to localStorage or server and so on.
Wrap reducer execute.
e.g. use redux-undo to implement 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 };
},
},
});
Wrap effect execute.
e.g. dva-loading has implement auto loading state with this hook.
HMR(Hot Module Replacement) related, currently used in babel-plugin-dva-hmr.
Specify extra reducers.
e.g. redux-form needs extra form
reducer:
import { reducer as formReducer } from 'redux-form'
const app = dva({
extraReducers: {
form: formReducer,
},
});
Specify extra StoreEnhancers.
e.g. use dva with redux-persist:
import { persistStore, autoRehydrate } from 'redux-persist';
const app = dva({
extraEnhancers: [autoRehydrate()],
});
persistStore(app._store);
Register model, view #Model for details.
Unregister model.
Only available after
app.start()
got called
Replace an existing model with a new one, comparing by the namespace. If no one matches, add the new one.
After called, old reducers
, effects
, subscription
will be replaced with the new ones, while original state is kept, which means it's useful for HMR.
Register router config.
e.g.
import { Router, Route } from 'dva/router';
app.router(({ history }) => {
return (
<Router history={history}>
<Route path="/" component={App} />
<Router>
);
});
Recommend using separate file to config router. Then we can do hmr with babel-plugin-dva-hmr. e.g.
app.router(require('./router'));
Besides, if don't need router, like multiple-page application, react-native, we can pass in a function which return JSX Element. e.g.
app.router(() => <App />);
Start application. selector
is optionally, if no selector
, it will return a function which return JSX element.
app.start('#root');
e.g. implement i18n with react-intl:
import { IntlProvider } from 'react-intl';
...
const App = app.start();
ReactDOM.render(<IntlProvider><App /></IntlProvider>, htmlElement);
model is the most important concept in dva.
e.g.
app.model({
namespace: 'todo',
state: [],
reducers: {
add(state, { payload: todo }) {
// Save data to state
return [...state, todo];
},
},
effects: {
*save({ payload: todo }, { put, call }) {
// Call saveTodoToServer, then trigger `add` action to save data
yield call(saveTodoToServer, todo);
yield put({ type: 'add', payload: todo });
},
},
subscriptions: {
setup({ history, dispatch }) {
// Subscribe history(url) change, trigger `load` action if pathname is `/`
return history.listen(({ pathname }) => {
if (pathname === '/') {
dispatch({ type: 'load' });
}
});
},
},
});
model includes 5 properties:
model's namespace.
models's initial state, it's priority is lower than opts.initialState
in dva()
.
e.g.
const app = dva({
initialState: { count: 1 },
});
app.model({
namespace: 'count',
state: 0,
});
Then, state.count is 1 after app.start()
.
Store reducers in key/value Object. reducer is the only place to modify state
. Triggered by action
.
(state, action) => newState
or [(state, action) => newState, enhancer]
View https://github.com/dvajs/dva/blob/master/packages/dva-core/test/reducers.test.js for details.
Store effects in key/value Object. Used for do async operations and biz logic, don't modify state
directly. Triggered by action
, could trigger new action
, communicate with server, select data from global state
and so on.
*(action, effects) => void
or [*(action, effects) => void, { type }]
。
type includes:
takeEvery
takeLatest
throttle
watcher
poll
View https://github.com/dvajs/dva/blob/master/packages/dva-core/test/effects.test.js for details.
Store subscriptions in key/value Object. Subscription is used for subscribing data source, then trigger action by need. It's executed when app.start()
.
({ dispatch, history }, done) => unlistenFunction
Notice: if we want to unregister a model with app.unmodel()
or app.replaceModel()
, it's subscriptions must return unsubscribe method.