如何使用派生类中的方法更改immutablejs记录?

时间:2018-01-05 17:07:31

标签: redux immutable.js

我有3个来自Record的类。前两个类的定义如下。

// Base.js
import {Record} from 'immutable';
import * as uuid from 'uuid';

export const Base = defaultValues => {
  return class extends Record({
    key: null,
    ...defaultValues,
  }) {
    constructor(props) {
      super(Object.assign({}, props, {key: (props && props.key) || uuid.v4()}));
    }
  };
};


// LOBase.js
import {Base} from './BaseModel';

export const LOBase = defaultValues => {
  return class extends Base({
    created_at: new Date(null),
    updated_at: new Date(null),
    deleted_at: new Date(null),
    isActive: new Boolean(),
    isDeleted: new Boolean(),
    publishState: new String(),
    ...defaultValues,
  }) {};
};

这是我从LOBase派生的最后一个类,我的问题出在那里。

// Question.js
import {List, Record, fromJS} from 'immutable';
import _ from 'lodash';
import {LOBase} from './base/LOBaseModel';

export class Question extends LOBase({
  id: '',
  name: 'test',
  description: '',
  questionType: 1,
  title: 'title',
  version: new String(),
  customData: {},

  //...
}) {
  insertOption() {
    let index = this.customData.options.length;

    this.updateIn(['customData', 'options'], options => {
      return options.splice(index, 0, {
        someGenericStuff: [],

        // ...
      });
    });

    return this;
  }

  static MultipleChoice() {
    let defaultCustomData = {
      options: [],

      //...
    };

    let question = new Question()
      .set('questionType', QUESTION_TYPE_MULTIPLE_CHOICE)
      .set('customData', new Record(defaultCustomData)())
      //...
      .insertOption()
      .insertOption()
      .insertOption();

    return question;
  }

  // ...
}

我使用let question = Question.MultipleChoice()创建一个新的Question实例。当我使用question.insertOption()时它工作正常。但是,当我在状态的reducer中执行此操作时,我收到错误消息“在调度中检测到状态突变”

如何在州内更改问题对象?我应该在这之前克隆原始记录吗? Immutablejs的做法是什么?

提前致谢。

1 个答案:

答案 0 :(得分:0)

insertOption使用this.updateIn但不返回或存储结果。 当您在函数末尾返回 this 时,实际上会返回相同的不可变记录而不进行更改。 所以,除非我在这里遗漏了什么,否则你应该选择:

insertOption() {
  let index = this.customData.options.length;

  return this.updateIn(['customData', 'options'], options => {
    return options.splice(index, 0, {
      someGenericStuff: [],

      // ...
    });
  });
}

updateIn将返回带有更新值的Record的新实例。

你没有添加你的状态结构和reducer(如果可以的话),但你应该确保每次返回一个新的状态对象,而不仅仅是更改问题字段。

顺便说一下,你是一个接一个地做一系列变异方法(set,set,updateIn)。从性能角度来看,这是不可取的。我建议用以下方式用withMutations替换它:

static insertOption(record) {
  let index = record.customData.options.length;

  return record.updateIn(['customData', 'options'], options => {
    return options.splice(index, 0, {
      someGenericStuff: [],

      // ...
    });
  });
}

static MultipleChoice() {
  // ...
  let question = new Question();
  question.withMutations(record => {
    record.merge({
     questionType: QUESTION_TYPE_MULTIPLE_CHOICE,
     customData: new Record(defaultCustomData)()
    })
    Question.insertOption(record);
  })
  return question;
}