关于redux中的reducer的两点疑问

1、既然reducer强调不可变数据的概念为何不直接返回一个深拷贝之后的state,例如_.cloneDeep
2、既然不能直接更改state,为何不利用Object.freeze,或者类似的方法让state不可改变

import { SET_BOOKS, ADD_BOOK, REMOVE_BOOK, CHANGE_BOOK_PRICE } from '../actions/book.js'

const initBooks = []

const books = (state, action) => {
    if (state === undefined) {
        state = initBooks
    }
    //或者运用性能更好的_.cloneDeep
    let tmpBooks = JSON.parse(JSON.stringify(state))
    switch (action.type) {
        case SET_BOOKS:
            return action.books
            break
        case ADD_BOOK:
            // return [...state,action.newBook]
            tmpBooks.push(action.newBook)
            return tmpBooks
            break
        case REMOVE_BOOK:
            return state.filter(item => {
                return item.id !== action.bookId
            })
            break
        case CHANGE_BOOK_PRICE:
            tmpBooks.forEach(item => {
                if(item.id===action.bookId){
                    item.price=action.newPrice
                }
            });
            return action.books
            break
        default:
            return state
    }
}

export default books
阅读 3.4k
2 个回答

问题1: 每次深拷贝是可以的,但是会浪费性能,因为不管你做了任何操作都会创立一个新的对象,特别是内容很多的对象,内存占用负担很大。
问题2:你说的没错,就是可以用Object. freeze来保证immutable,这也是很多轻量级的immutable库内部的实现方式,可以看 seamless-immutable,immutable-helper这类库。

题外话,immutable 保证了 reducer 在内部数据变化后,返回一个新对象,用处是判断两次数据时,只需要进行一次 reference 判断,而不用 deepEqual 判断,从而节省性能开销。

不知道我跟你想的一不一样,可以看下combineReducers的源码:

var hasChanged = false
    var nextState = {}
    for (var i = 0; i < finalReducerKeys.length; i++) {
      var key = finalReducerKeys[i]
      var reducer = finalReducers[key]
      var previousStateForKey = state[key]
      var nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        var errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    return hasChanged ? nextState : state

关键点在于每次reducer返回新的state会跟旧的state做===对比,如果false认为store改变,从而触发页面重绘,如果true,则认为不变,不会触发重绘。所以reducer返回新的state是为了通知redux让页面重绘。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题