原理概述
- 定义一个
Store类
store.state用于存储状态数据
store.dispatch(action)来更改state状态
reducer(state,action)函数来定义和关联action与state变更操作的对应关系
store.subscribe(callback)来收集state更新后回调函数
实现
Store Class
class Store {
constructor(initialState, reducers) {
this.state = initialState || {};
this.reducer = this.combineReducers(reducers);
this.subs = [];
}
getState = () => this.state;
setState = state => this.state = state;
subscribe = callback => this.subs.push(callback.bind({
state: this.getState()
}));
dispatch = action => {
this.setState(this.reducer(this.getState(), action));
this.subs.forEach(sub => sub());
}
combineReducers = (reducers) => {
return (state = this.getState(), action) => {
Object.keys(reducers).forEach(fnKeyFromReducer => {
let newState = reducers[fnKeyFromReducer](state, action);
Object.assign(state, newState);
});
return state;
}
}
}
createStore
function createStore(initialState = {}, reducers) {
let store = new Store(initialState, reducers);
return store;
}
demo
<body>
<div id="app"></div>
<button onclick="add()">add</button>
<button onclick="reduce()">reduce</button>
<script>
let obj = {
count: 0
};
let reducers = {
add: function (state, action) {
if (action.type === 'add') {
return Object.assign({}, state, {
count: state.count + 1
})
}
return state;
},
reduce: function (state, action) {
if (action.type === 'reduce') {
return Object.assign({}, state, {
count: state.count - 1
})
}
return state;
}
};
let store = createStore(obj, reducers);
store.subscribe(function () {
console.log(obj === this.state);
document.querySelector('#app').textContent = this.state.count;
});
function add() {
store.dispatch({
type: 'add',
})
}
function reduce() {
store.dispatch({
type: 'reduce',
})
}
</script>
</body>
实现中间件 applyMiddleware
Store
class Store {
constructor(initialState, reducers) {
this.state = initialState;
this.reducer = this.combineReducers(reducers);
this.subs = [];
this.initialDispatch();
}
getState = () => this.state;
setState = state => this.state = state;
subscribe = callback => this.subs.push(callback.bind({
state: this.getState()
}));
initialDispatch = (dispatch) => {
if (dispatch) {
return this.dispatch = dispatch;
}
this.dispatch = action => {
this.setState(this.reducer(this.getState(), action));
this.subs.forEach(sub => sub());
}
}
combineReducers = (reducers) => {
return (state = this.getState(), action) => {
Object.keys(reducers).forEach(fnKeyFromReducer => {
let newState = reducers[fnKeyFromReducer](state, action);
Object.assign(state, newState);
});
return state;
}
}
}
createStore && applyMiddleware
function createStore(initialState = {}, reducers, enhancedDispatch) {
let store = new Store(initialState, reducers);
store.initialDispatch(enhancedDispatch(store));
return store;
}
let applyMiddleware = (...middlewareArray) => (store) => {
if (middlewareArray.length) {
let innerMethod;
middlewareArray.forEach(fn => {
const smStore = {
getState: store.getState
}
if (!innerMethod) innerMethod = fn(smStore)(store.dispatch);
else innerMethod = fn(smStore)(innerMethod);
});
return innerMethod;
}
}
redux 实现 applyMiddleware 的方式
export default function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
export default function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
demo
<body>
<div id="app"></div>
<button onclick="add()">add</button>
<button onclick="reduce()">reduce</button>
<script>
let obj = {
count: 0
};
let reducers = {
add: function (state, action) {
if (action.type === 'add') {
return Object.assign({}, state, {
count: state.count + 1
})
}
return state;
},
reduce: function (state, action) {
if (action.type === 'reduce') {
return Object.assign({}, state, {
count: state.count - 1
})
}
return state;
}
};
let logMiddleware = (store) => (next) => (action) => {
console.log('log middle ware --- start');
next(action);
console.log('log middle ware --- end');
}
const loggerMiddleware = (store) => (next) => (action) => {
console.log('---before state::', store.getState());
console.log('---doing dispatch type::', action.type);
next(action);
console.log('---after state::', store.getState());
console.log('---------divide--------');
}
let enhancedDispatch = applyMiddleware(loggerMiddleware, logMiddleware);
let store = createStore(obj, reducers, enhancedDispatch);
store.subscribe(function () {
console.log(obj === this.state);
document.querySelector('#app').textContent = this.state.count;
});
function add() {
store.dispatch({
type: 'add',
})
}
function reduce() {
store.dispatch({
type: 'reduce',
})
}
</script>
</body>