react dva 复习subscriptions: setup
- Flux,单向数据流方案,以 Redux 为代表
- Reactive,响应式数据流方案,以 Mobx 为代表
dva = React-Router + Redux + Redux-saga
import dva from 'dva';
const App = () => <div>Hello dva</div>;
// 创建应用
const app = dva();
// 注册视图
app.router(() => <App />);
// 启动应用
app.start('#root');
// 继承react-redux
mport { connect } from 'dva';
function mapStateToProps(state) {
return { todos: state.todos };
}
connect(mapStateToProps)(App);
/// dva最简单模型
// 创建应用
const app = dva();
// 注册 Model
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state) { return state + 1 },
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
});
// 注册视图
app.router(() => <ConnectedApp />);
// 启动应用
app.start('#root');
// 数据层modle
app.model
dva 提供 app.model 这个对象,所有的应用逻辑都定义在它上面。
const app = dva();
// 新增这一行
app.model({ /**/ });
app.router(() => <App />);
app.start('#root');
// modle对象的例子
Model 对象的例子
{
namespace: 'count',
state: 0,
reducers: {
add(state) { return state + 1 },
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
}
// 属性
Model 对象的属性
namespace: 当前 Model 的名称。整个应用的 State,由多个小的 Model 的 State 以 namespace 为 key 合成
state: 该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出
reducers: Action 处理器,处理同步动作,用来算出最新的 State
effects:Action 处理器,处理异步动作
#
call 和 put
dva 提供多个 effect 函数内部的处理函数,比较常用的是 call 和 put。
call:执行异步函数
put:发出一个 Action,类似于 dispatch
#
剧透:dva 是个函数,返回一了个 app 的对象。
剧透2:目前 dva 的源码核心部分包含两部分,dva 和 dva-core。前者用高阶组件 React-redux 实现了 view 层,后者是用 redux-saga 解决了 model 层。
setupApp(app) 是从 dva 里传过来的,主要是使用 patchHistory 函数代理 history.linsten,即强化了 redux 和 router 的联系,是的路径变化可以引起 state 的变化,进而听过监听 state 的变化来触发回调。
这也是 core 中唯一使用 this 的地方,逼得 dva 中必须使用 oldStart.call(app) 来进行调用。
// Setup app
setupApp(app);
// Run subscriptions
const unlisteners = {};
for (const model of this._models) {
if (model.subscriptions) {
unlisteners[model.namespace] = runSubscription(model.subscriptions, model, app, onError);
}
}
setup用来监听变化router变化
subscriptions: {
setup({ dispatch, history }) {
history.listen((location) => {
if (location.pathname === '/stock/reportDiff') {
dispatch({
type: 'queryDepot',
payload: { ...location.query, rows: 10 },
});
dispatch({
type: 'queryDate',
payload: {},
});
}
});
},
},