redux实现

198 阅读2分钟

Redux 是 JavaScript 状态容器,提供可预测化的状态管理

三大原则

单一数据源

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中

State 是只读的

唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象

使用纯函数来执行修改

为了描述 action 如何改变 state tree ,你需要编写 reducers

Action

action的本质是javascript对象,action 内必须使用一个字符串类型的type字段来表示将要执行的动作

//action.js
//ADD_BOOK 新增book
export function addBook(data) {
  return { type: 'ADD_BOOK', data }
}
//DEL_BOOK 删除book
export function delBook(id) {
  return { type: 'DEL_BOOK', id }
}

Reducers

Reducers 指定了应用状态的变化如何响应 actions 并发送到 store,reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state

//redecures
function books(state = [], action) {
  switch (action.type) {
    case 'ADD_BOOK':
      return [
        ...state,
        action.data
      ]
    case 'DEL_BOOK':
      return state.filter(v => v.id !== action.id)
    default:
      return state
  }
}

function app(state = {}, action) {
  return {
    books: books(state.books, action)
  }
}


export default app

Reducers合成

实际开发过程中,可能会有多个reducers函数,每个reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据


function app(state = {}, action) {
  return {
    books: books(state.book, action),
    music: music(state.music, action),
    ...
    ...
    ...
  }
}

combineReducers

redux提供combineReducers方法来实现app方法,减少样板代码


import { combineReducers } from 'redux'

const app = combineReducers({
  books,
  music
})
}

combineReducers方法实现


export default function(reducers){
    const keys = Object.keys(reducers)
    const newReducers = {}

    keys.forEach(item => {
        if(typeof reducers[item] === 'function'){
            newReducers[item] = reducers[item]
        }
    })

    return function(state = {}, action){
        const keys = Object.keys(newReducers)
        keys.forEach(item => {
        	//拿到旧的state
            const oldState = state[item]
            //执行reducers获取新的state
            const data = newReducers[item](oldState, action)
            state[item] = data
        })
        return state
    }
}

Store

getState() 方法获取 state

dispatch(action) 方法更新 state

subscribe(listener) 注册监听器

subscribe(listener) 返回的函数注销监听器

import {createStore} from 'redux'
import {
    addBook,
    delBook
  } from './actions'
  
import todoApp from './reducers'

const store = createStore(todoApp)

store.dispatch(addBook({
  id: 'N0000001',
  name: '西游记'
}))

setTimeout(() => {
  store.dispatch(delBook('N0000001'))
}, 1000)


 store.subscribe(() => {
  console.log(store.getState())
})

createStore

创建一个 Redux store 来以存放应用中所有的 state。应用中应有且仅有一个 store。

export default function createStore(reducer, preloadedState, enhancer){
    let currentReducer = reducer
    let currentState = preloadedState
    let currentListeners = []
    let nextListeners = currentListeners
    let isDispatching = false
    

    function subscribe(listener) {
        if (isDispatching) {
            throw new Error('isDispatching...')
        }
    
        let isSubscribed = true
        nextListeners.push(listener)
        return function unsubscribe() {
          if (!isSubscribed) {
            return
          }
          if (isDispatching) {
            throw new Error('isDispatching...')
          }
          isSubscribed = false
          //移除监听
          nextListeners.splice(nextListeners.indexOf(listener), 1)
        }
      }



    function dispatch(action){
        try {
            isDispatching = true
            //获取新的状态树
            currentState = currentReducer(currentState, action)
        } 
        finally {
            isDispatching = false
        }
        const listeners = (currentListeners = nextListeners)
        //执行监听器
        for (let i = 0; i < listeners.length; i++){
        const listener = listeners[i]
            listener()
        }
        return action
    }
    
    function getState() {
        if (isDispatching) {
            throw new Error('isDispatching...')
        }
        //返回新的状态树
        return currentState
    }
    return{
        getState,
        dispatch,
        subscribe
    }
}