yield call(delay, 1000);
yield put({ type: ‘add’ });
},
},
});
// 注册视图
app.router(() => );
// 启动应用
app.start(‘#root’);
Dva底层原理和部分关键实现
背景介绍
-
整个 dva 项目使用 lerna 管理的,在每个 package 的 package.json 中找到模块对应的入口文件,然后查看对应源码。
-
dva 是个函数,返回一了个 app 的对象。
-
目前 dva 的源码核心部分包含两部分,dva 和 dva-core。前者用高阶组件 React-redux 实现了 view 层,后者是用 redux-saga 解决了 model 层。
dva[15]
dva 做了三件比较重要的事情:
-
代理 router 和 start 方法,实例化 app 对象
-
调用 dva-core 的 start 方法,同时渲染视图
-
使用 react-redux 完成了 react 到 redux 的连接。
// dva/src/index.js
export default function (opts = {}) {
// 1. 使用 connect-react-router 和 history 初始化 router 和 history
// 通过添加 redux 的中间件 react-redux-router,强化了 history 对象的功能
const history = opts.history || createHashHistory();
const createOpts = {
initialReducer: {
router: connectRouter(history),
},
setupMiddlewares(middlewares) {
return [routerMiddleware(history), …middlewares];
},
setupApp(app) {
app._history = patchHistory(history);
},
};
// 2. 调用 dva-core 里的 create 方法 ,函数内实例化一个 app 对象。
const app = create(opts, createOpts);
const oldAppStart = app.start;
// 3. 用自定义的 router 和 start 方法代理
app.router = router;
app.start = start;
return app;
// 3.1 绑定用户传递的 router 到 app._router
function router(router) {
invariant(
isFunction(router),
[app.router] router should be function, but got ${typeof router}
,
);
app._router = router;
}
// 3.2 调用 dva-core 的 start 方法,并渲染视图
function start(container) {
// 对 container 做一系列检查,并根据 container 找到对应的DOM节点
if (!app._store) {
oldAppStart.call(app);
}
const store = app._store;
// 为HMR暴露_getProvider接口
// ref: https://github.com/dvajs/dva/issues/469
app._getProvider = getProvider.bind(null, store, app);
// 渲染视图
if (container) {
render(container, store, app, app._router);
app._plugin.apply(‘onHmr’)(render.bind(null, container, store, app));
} else {
return getProvider(store, this, this._router);
}
}
}
function getProvider(store, app, router) {
const DvaRoot = extraProps => (
{router({ app, history: app._history, …extraProps })}
);
return DvaRoot;
}
function render(container, store, app, router) {
const ReactDOM = require(‘react-dom’); // eslint-disable-line
ReactDOM.render(React.createElement(getProvider(store, app, router)), container);
}
我们同时可以发现 app 是通过 create(opts, createOpts)