redux剖析
redux
redux是flux的进化版,flux流程图(图片来源:http://caibaojian.com/react/flux.html):
Redux流程图
combineReducers
function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers);
// 组合后的reducer
const finalReducers = {};
// 如果ruducer不是函数,将其过滤
for(let i=0, len=reducerKeys.length; i<len; i++) {
let key = reducerKeys[i];
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
const finalReducerKeys = Object.keys(finalReducers);
// 返回值为组合后的reducer函数,返回总的state
return function combination(state={}, action) {
// state是否改变
let hasChanged = false;
// 改变后的state
let nextState = {};
for (let i=0, len=finalReducerKeys.length; i<len; i++) {
let key = finalReducerKeys[i];
// 获取key对应的reducer
let reducer = finalReducers[key];
// state树与finalReducers的key是一一对应的
let preStateForKey = state[key];
// 执行reducer获取nextState
let nextStateForKey = reducer(preStateForKey, action);
nextState[key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== preStateForKey;
}
// 如果状态改变,返回nextState; 否则返回state;
return hasChanged ? nextState : state;
}
}
createStore
function createStore(reducer, enhancer) {
if (enhancer) {
return enhancer(createStore)(reducer);
}
let currentState = {};
let currentListeners = [];
let isDispatching = false;
function getState() {
return currentState
}
function subscribe(listener) {
currentListeners.push(listener);
let isSubscribed = true;
// 返回一个取消订阅函数
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) { // reducer是否正在执行
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See http://redux.js.org/docs/api/Store.html##subscribe for more details.'
)
}
isSubscribed = false // 重置已订阅标志位
const index = currentListeners.indexOf(listener)
currentListeners.splice(index, 1)
}
}
function dispatch(action) {
try {
isDispatching = true;
currentState = reducer(currentState, action);
} finally {
isDispatching = false
}
currentListeners.forEach(listener => {
listener();
})
return action;
}
return {getState, subscribe, dispatch};
}
applyMiddleware
可以参考我的另一篇博客redux applyMiddleware
// middleware: ({ getState, dispatch }) => next => action;
// midddleware只是包装了store的dipatch方法
function logger ({ getState }) {
return (next) => (action) => {
console.log('will dispatch: ', action);
let returnValue = next(action);
return returnValue;
}
}
function applyMiddleware (...middlewares) {
return createStore => (...args) => {
const store = createStore(...args);
const dispatch = store.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
}
}
}
compose
// 从右到左返回合成后的函数
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)));
}
function add (x) {return x + 1}
function pow (x) {return Math.pow(x, 2)}
compose()(3); // 3
compose(add, pow)(3); // 10
compose(pow, add)(3); // 16
react-redux
Provider
class Provider extends React.Component {
static childContextTypes = {
store: PropTypes.object
}
constructor(props, context) {
super(props, context);
this.store = props.store;
}
getChildContext() {
return {store: this.store};
}
render() {
return this.props.children;
}
}
connect
const connect = (mapStateToProps = state => state, mapDispatchToProps = {}) => {
(WrapContainer) => {
return class ConnectComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
props: {}
}
}
componentDidMount() {
const { store } = this.context;
store.subscribe(() => this.update());
this.update();
}
update() {
const { store } = this.context;
const stateProps = mapStateToProps(store.getState())
const dispatchProps = bindActionCreator(mapDispatchToProps, store.dispath);
this.setState({
props: {
...this.state.props,
...stateProps,
...dispatchProps
}
})
}
render() {
return <WrapContainer {...this.state.props}></WrapContainer>
}
}
}
}