在Redux中使Reducer不可变

时间:2016-06-25 14:03:37

标签: javascript reactjs redux immutable.js

我刚刚开始使用ImmutableJS,我想制作一个REDcer永久变形器。我已经读过我需要将我的减速器转换回来才能使其工作。任何人都可以想出如何使这项工作的答案?本身我收到错误消息:" INCREASE_NUMBER.toObject()不是函数"这是代码(如下):

import { INCREMENT } from '../actionTypes/default'
import { Map, toObject } from 'immutable'

const INCREASE_NUMBER = (state = Map({number: 0}), action) => {
  switch(action.type) {
    case INCREMENT:
    return state.merge({number: state.number + 1})
    default:
    return state
  }
};
INCREASE_NUMBER.toObject()

module.exports = INCREASE_NUMBER

3 个答案:

答案 0 :(得分:3)

基于你的问题,你似乎并没有真正理解不变性,因此我首先质疑你需要使用ImmutableJS的合法性。您不必使用ImmutableJS来编写非变异状态转换。

我不需要插座盖以防止自己将金属物体戳入电源插座。我宁可不要触电,所以我不会把所有东西都插到插座上。它并不复杂。

您最好对您正在使用的工具有一个深入了解。您应该知道JavaScript运算符/函数/方法何时改变数据以及何时不改变数据。如果您认为ImmutableJS可以保护您免受自己的无知,那么您将犯一个大错误。你会在某些时候遇到问题并且不知道如何诊断它们,因为你没有花时间去理解你在做什么。

你的reducer可以用非废话的vanilla JavaScript编写

import { INCREMENT } from '../actionTypes/default'

const initialState = {number: 0}

const increaseNumberReducer = (state, action) => {
  switch (action.type) {
    case INCREMENT:
      return {number: state.number + 1}
    default:
      return state
  }
}

export default increaseNumberReducer

这里没有突变。从代码编写的方式来看,变异根本不可能。我们正在读取来自state的值,但此处没有可以到现有state对象的代码。 state不是不可变的对象,但您也不是一个愚蠢的开发人员。如果你写了一些代码来改变state对象,那就是你自己的错。如果你在电源插座上闲逛,你只能责备自己。

我可以轻松写下

// non-mutating state transformation
case INCREMENT:
  return Object.assign({}, state, {number: state.number + 1})

......你应该知道它与

的区别
// mutating state transformation
case INCREMENT:
  return Object.assign(state, {number: state.number + 1})

同样,你应该知道

之间的区别
// non-mutating array transformation
[1,2,3].concat([4])

......还有这个

// mutating array transformation
[1,2,3].push(4)

这个怎么样

// mutating sort
[4,2,1,3].sort()

......还有这个

// non-mutating sort
[4,2,1,3].slice(0).sort()

当然,如果您有一个很棒的应用程序,有人可能会认为在您的数据周围添加一个小的不变性安全预防措施是有意义的。这可能会阻止无知的开发人员在意外突变state时不应该这样做。对我来说,这不是一个有效的解决方案。如果这是一个redux应用程序,那么你的开发人员应该对redux哲学有深入的了解,这意味着reducers是纯函数而且state永远不会被变异......知识和智慧是无可替代的。

密切了解JavaScript。了解您正在使用的工具。确定各种方法的优缺点。了解各种技术的“成本”。知道何时何地可以妥协。如果您仍然决定在所有这一切结束时使用ImmutableJS,那么您将知道为什么您选择它并且您将知道它带来的收益/损失。

答案 1 :(得分:1)

reducer是一个函数 - 一个不能保持任何状态的纯函数。例如。对于减速器而言,不变性是没有意义的。

不变性是指数据结构,而不是函数。在React和Redux中,最好使您的状态不可变,例如:以一种始终返回不可变数据结构的方式设计reducer函数。但这并不适用于减速器本身 - 这只是一个功能。

import { INCREMENT } from '../actionTypes/default'
import { Map } from 'immutable'

export default (state = Map({number: 0}), action = {}) => {
    switch (action.type) {
        case INCREMENT:
            // return new Immutable data structure here
            return state.update('number', num => num + 1);
        default:
             return state;
    }
};

上面的示例与原始代码非常相似,但我们不需要来自immutableJS的toObject,并且我已经优化了状态更新。

这里有什么不可变的?所有州:

  • 默认状态,作为state参数的默认值,是一个新的不可变Map;
  • INCREMENT操作后的修改状态(Map.prototype.update()返回一个新的不可变实例)。

这个reducer函数总是返回不可变数据,这很好。这就是在reducers的情况下实现不变性的方式:它们的返回值应该是不可变的。

答案 2 :(得分:0)

在这种情况下,INCREASE_NUMBER只是一个函数,因此调用它上面的toObject毫无意义。

据我所知,toObject是一个可以在不可变对象上调用的函数,可以将它们转换为JS对象。但是,还有merge函数用于扩展Map,状态值似乎是Map,而不是JS对象,那么为什么要使用{{} 1}}在这里的任何地方?

只需删除toObject行。

如果目的是让reducer返回一个JS对象而不是toObject,那么你必须把它放在Map语句中的函数中。但是,采用return并返回一个对象似乎是对减速器的错误方法。进出的状态应该是相同的形状。