Appearance
基本计数器
本节目标:理解“基本计数器”的核心思路,并能把它用于实际开发或面试表达。 使用
Src/index.js
importReact from
'react';
importdva,{ connect } from
'./dva';
constapp =
dva();
app.model({namespace:
'counter',// 每个命名空间都有自己的状态 state: { number: 0 },// 还有自己的处理器reducerreducers: {// reducers对象key就相当于actionType// 值是本state对应的处理函数 // state是此命名空间下的分状态,
add(state,action){return { number:
state.number+ 1 };},
minus(state,action){return { number:
state.number- 1 };}
}
});
functionCounter(props){return (
<div><p>{props.number}</p><buttononClick={()=\>
props.dispatch({ `type:` `'counter/add'`
})}>+</button></div>)
}
constConnectedCounter =
connect(//conenct第二个参数如果没有传,默认会把store.dispatch当成参数传给组件 state =\>
state.counter
)(Counter);
//定义要渲染的内容
app.router(()=\>
<ConnectedCounter/>);
//开始渲染
app.start('#root');实现
src\dva\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import prefixNamespace from './prefixNamespace';
export { connect }
function dva() {
const app = {
//存放model的数组
_models: [],
//函数,用来往model数组中添加model元素
model,
//定义路由的函数
router,
//存放路由函数的变量
_router: null,
//开启渲染
start
}
function model(modelObject) {
const prefixedModel = prefixNamespace(modelObject);
app._models.push(prefixedModel);
return prefixedModel
}
function router(routerConfig) {
app._router = routerConfig;
}
let initialReducers = {};
function start(selector) {
for (const model of app._models) {
initialReducers[model.namespace] = getReducer(model);
}
let rootReducer = createReducer();
let store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
{app._router()}
</Provider>, document.querySelector(selector)
);
}
function createReducer() {
return combineReducers(initialReducers);
}
return app;
}
function getReducer(model) {
let { state: initialState, reducers } = model;
return (state = initialState, action) => {
let reducer = reducers[action.type];
if (reducer) return reducer(state, action);
return state;
}
}
export default dva;
/**
* connect => Provider
* Provider => store
* store => reducer
*获取每个model的reducers对象,把每个对象变成一个函数
*然后再通过combineReducers合并成一个
reducer
*/src\dva\prefixNamespace.js
import { NAMESPACE_SEP } from './constants';
/**
*把一个对象的key从一个老的值变成
namespace/老的值
* @param {*} obj
* @param {*} namespace
*/
function prefix(obj, namespace) {
//[add,minus]
return Object.keys(obj).reduce(function (memo, key) {
const newKey = `${namespace}${NAMESPACE_SEP}${key}`;
memo[newKey] = obj[key];
return memo;
}, {});
}
export default function prefixNamespace(model) {
if (model.reducers) {
model.reducers = prefix(model.reducers, model.namespace);
}
return model;
}src\dva\constants.js
export const NAMESPACE_SEP = '/';