汪微的博客
zane,做一个有思维的开发者

汪微的博客

redux v3.7.2源码解读与学习之 createStore

2017年12月17日66 browse

redux是什么、有什么作用,解决什么问题,如果你还不知道,请先去这里: redux中文文档

下面的文章适合对redux有一定理解和使用经验的人

项目github地址:https://github.com/wangweianger/redux-source-code-learning

如果你觉得对你有帮助的话记得给我一个star呢

createStore 是redux中最核心的代码,下面我们一步一步来实现一个简易版的 createStore。


1.新建一个simpleCreateStore.js 文件,创建一个createStore函数

var ActionTypes = {
  INIT: '@@redux/INIT'
}
function createStore(reducer, preloadedState, enhancer){}



2.createStore内部添加,getState、subscribe、dispatch、replaceReducer 4个空函数,并return出来

function createStore(reducer, preloadedState, enhancer){
    function getState(){}
    function subscribe(){}
    function dispatch(){}
    function replaceReducer(){}

    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }

}



3.我们来给点参数使函数运行起来,代码如下:

const ADD_TODO = 'ADD_TODO'
function todos(state = [], action) {
    switch (action.type) {
        case 'ADD_TODO':
            return state.concat([ action.text ])
        default:
            return state
    }
}
let store = createStore(todos,[ 'Use Redux' ])
console.log(store)


下面我们来一一的实现这个几个方法的内容。


4.实现getState方法

getState方法最简单直接返回函数内定义的currentReducer变量即可,代码如下:

function createStore(reducer, preloadedState, enhancer){
   let currentState = preloadedState

    function getState(){
        return currentState
    }

    function subscribe(){}
    function dispatch(){}
    function replaceReducer(){}

    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }

}



5.实现dispatch方法,此方法是redux的核心方法

var ActionTypes = {
  INIT: '@@redux/INIT'
}

function createStore(reducer, preloadedState, enhancer){
    let currentState = preloadedState
    let currentReducer = reducer

    function getState(){
        return currentState
    }
    function subscribe(){}
    function dispatch(action){
        currentState = currentReducer(currentState, action)
        return action
    }
    function replaceReducer(){}
    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }
}


const ADD_TODO = 'ADD_TODO'
function todos(state = [], action) {
    switch (action.type) {
        case 'ADD_TODO':
            return state.concat([ action.text ])
        default:
            return state
    }
}

let store = createStore(todos,[ 'Use Redux' ])
console.log(store.getState())


代码很简单,现在调用 store.getState() 试试吧,是不是得到了 ["Use Redux"] 这个值呢。

现在来调用一下dispatch这个方法吧,看看是不是能得到 ["Use Redux", "Read the docs"] 呢?

let actions = store.dispatch({
  type: 'ADD_TODO',
  text: 'Read the docs'
})



6.实现subscribe方法,并返回一个unsubscribe的方法,相应的dispatch运行监听变化:

function createStore(reducer, preloadedState, enhancer){
    let currentState = preloadedState
    let currentReducer = reducer
    let nextListeners = []

    function getState(){
        return currentState
    }
    function subscribe(listener){
        nextListeners.push(listener)
        return function unsubscribe() {
            const index = nextListeners.indexOf(listener)
            nextListeners.splice(index, 1)
        }
    }
    function dispatch(action){
        currentState = currentReducer(currentState, action)
        for (let i = 0; i < nextListeners.length; i++) {
            const listener = nextListeners[i]
            listener()
        }
        return action
    }
    function replaceReducer(){}

    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }
}


方法写好了我们来写个测试案例:

let currentValue
function handleChange() {
  let previousValue = currentValue
  currentValue = store.getState()
  if (previousValue !== currentValue) {
    console.log('store数据从', previousValue, '变为', currentValue)
  }
}

let unsubscribe = store.subscribe(handleChange)


掉一下dispatch方法看看日志记录吧。


7.实现replaceReducer方法,此方法也很简单

function createStore(reducer, preloadedState, enhancer){
    let currentState = preloadedState
    let currentReducer = reducer
    let nextListeners = []

    function getState(){
        return currentState
    }
    function subscribe(listener){
        nextListeners.push(listener)
        return function unsubscribe() {
            const index = nextListeners.indexOf(listener)
            nextListeners.splice(index, 1)
        }
    }
    function dispatch(action){
        currentState = currentReducer(currentState, action)
        for (let i = 0; i < nextListeners.length; i++) {
            const listener = nextListeners[i]
            listener()
        }
        return action
    }
    function replaceReducer(nextReducer) {
        currentReducer = nextReducer
        dispatch({ type: ActionTypes.INIT })
    }

    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }
}



9.最后运行createStore函数式初始化一次dispatch, dispatch({ type: ActionTypes.INIT })

最终代码如下:

var ActionTypes = {
  INIT: '@@redux/INIT'
}

function createStore(reducer, preloadedState, enhancer){
    let currentState = preloadedState
    let currentReducer = reducer
    let nextListeners = []

    function getState(){
        return currentState
    }
    function subscribe(listener){
        nextListeners.push(listener)
        return function unsubscribe() {
            const index = nextListeners.indexOf(listener)
            nextListeners.splice(index, 1)
        }
    }
    function dispatch(action){
        currentState = currentReducer(currentState, action)
        for (let i = 0; i < nextListeners.length; i++) {
            const listener = nextListeners[i]
            listener()
        }
        return action
    }
    function replaceReducer(nextReducer) {
        currentReducer = nextReducer
        dispatch({ type: ActionTypes.INIT })
    }
    dispatch({ type: ActionTypes.INIT })
    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer
    }
}

//-------------------测试代码---------------------------

const ADD_TODO = 'ADD_TODO'
function todos(state = [], action) {
    switch (action.type) {
        case 'ADD_TODO':
            return state.concat([ action.text ])
        default:
            return state
    }
}

let store = createStore(todos,[ 'Use Redux' ])

let currentValue
function handleChange() {
  let previousValue = currentValue
  currentValue = store.getState()
  if (previousValue !== currentValue) {
    console.log('store数据从', previousValue, '变为', currentValue)
  }
}

let unsubscribe = store.subscribe(handleChange)

let actions = store.dispatch({
  type: 'ADD_TODO',
  text: 'Read the docs'
})

console.log(store.getState())



OK经过上面的一通敲打之后,其实你已经完成了一次redux  createStore.js源码的构建,现在再去看看我github项目中对createStore.js的代码备注吧,相信你现在能很顺畅的自上而下的熟读。

贴一张图片:




接下来我们进入到redux的另一个核心工具方法 combineReducers

redux v3.7.2源码解读与学习之 combineReducers


博主 zane 发表于 2017-12-17 13:19:50,添加在了 redux 标签下

打赏

您的支持将鼓励我继续努力与分享。

扫码打赏,建议金额1-10元

提醒:打赏金额将直接进此方账号,无法退款,请您谨慎操作。

评论

正在加载验证码......

提交