【问题标题】:How to change property of item in ImmutableList({}) inside Immutable.Map({})如何在 Immutable.Map({}) 中更改 ImmutableList({}) 中项目的属性
【发布时间】:2016-08-02 19:39:43
【问题描述】:

如何更改ImmutableList({}) 中位于Immutable.Map({}) 内的项目的属性?

我有:

const initialState = Immutable.Map({
    width: window.board.width,
    height: window.board.height,
    lines: Immutable.List([
        Immutable.Map({id: 1, active: false, name: 'Some name'}),
        Immutable.Map({id: 2, active: false, name: 'Sad name'}),
        Immutable.Map({id: 3, active: true, name: 'Cool name'})
    ])
});

假设我想在列表中设置带有id 1 的项目。然后将其属性 active 更改为 true。我还想将 List 中所有其他项目的属性 active 设置为 false。

我该怎么做?提前非常感谢。

编辑(最终解决方案):

export function activateLine(lineId) {
    return function (dispatch, getState) {
        const updatedLines = getState().board.update('lines', Immutable.List(),
            (oldList) => oldList.map((listItem) => {
                return listItem.set("active", (listItem.get("id") === lineId));
            })).get('lines');

        return dispatch({
            type: types.ACTIVATE_LINE,
            payload: updatedLines
        });
    };
}

【问题讨论】:

  • 更改不可变对象是什么意思?关键是你不能;你必须复制和合并...
  • 我想用新值返回新的不可变映射。
  • 如何复制和合并它?你能给我举个例子吗?这正是我正在寻找的。​​span>
  • 我不知道我对 javascript 有点陌生。我认为在 redux 中拥有不可变状态是一个好主意。不过这很痛苦,因为我对不可变 API 并不熟悉,这对于没有过程编程经验的人来说非常混乱。
  • 是的,只需将整个对象包装在immutable.fromJS({...your object}) 中,那么整个对象将是不可变的,您不必再细分每个部分。

标签: javascript reactjs immutability immutable.js


【解决方案1】:

您可以像这样遍历不可变对象(尽管我强烈建议您将整个对象设置为不可变对象)。您可以通过使用不可变本身来减少代码行并使其更优雅 -

const changeImmutableObject = initialState.update('lines', Immutable.List(),
    (oldList) => oldList.map((listItem) => {
        if(listItem.get("id") === 1) {
            return listItem.set("active", true);
        } else {
            return listItem.set("active", false);
        }
    })
  )

查看工作小提琴 - https://jsfiddle.net/o04btr3j/214/

这会更新对象内的 list 键(如果它不存在,则默认为不可变列表),然后映射属性。如果 id 为 1,则将 active 设置为 true,否则将 active 设置为 false。

你也可以只 initialState.toJS() 你的不可变对象并在纯 js 中执行你的逻辑,或者执行 immutableobject.get('property') 并修改然后将其设置回你的对象中,但是我建议你只使用内置的方法不可变,因为它代码少得多

另外,如果我没记错的话,你可以这样做:

const initialState = Immutable.fromJS({
width: window.board.width,
height: window.board.height,
lines:[
    {id: 1, active: false, name: 'Some name'},
    {id: 2, active: false, name: 'Sad name'},
    {id: 3, active: true, name: 'Cool name'}
]
});

你可以通过 immutable.fromJS() 一个对象把它变成一个不可变对象。并且所有不可变对象都应该有一个 .toJS 方法,以将它们转换回常规的 javascript 对象/列表/任何东西。

【讨论】:

    【解决方案2】:

    我在 link to solution on jsbin.com 上创建了轻巧的示例

    const initialState = Immutable.Map({
        lines: Immutable.List([
            Immutable.Map({id: 1, active: false, name: 'Some name'}),
            Immutable.Map({id: 2, active: false, name: 'Sad name'}),
            Immutable.Map({id: 3, active: true, name: 'Cool name'})
        ])
    });
    
    
    console.log('initialState', initialState.toJS())
    
    // update lines, map over items and set active to false
    const stateLinesAllNotActive = initialState.updateIn(
      ['lines'], 
      items => items.map((item) => item.set('active', false)) 
    )
    
    console.log('stateLinesAllNotActive', stateLinesAllNotActive.toJS())
    
    // lines and key for item with id === 1, then set active to this item
    const stateFirstActive = stateLinesAllNotActive.updateIn(
      [
        'lines', 
        stateLinesAllNotActive.get('lines').findIndex((item) => (item.get("id") === 1))
      ],
      item => item.set("active", true)
    )
    
    console.log('stateFirstActive', stateFirstActive.toJS())
    

    【讨论】:

    • 感谢您的宝贵时间。不过,我刚刚接受了 ajmajmajma 的回答。
    【解决方案3】:

    以下内容应该可行,但是,正如有人所说...我认为完整更新可能会更好...

    const initialState = Immutable.Map({
        lines: Immutable.List([
            Immutable.Map({id: 1, active: false, name: 'Some name'}),
            Immutable.Map({id: 2, active: false, name: 'Sad name'}),
            Immutable.Map({id: 3, active: true, name: 'Cool name'})
        ])
    });
    
    let lines = initialState.get('lines'); 
    let id = 1; // what you want update...
    let updater = item => {
      let updated = item.set('name', "Giuseppe");
      
      return updated;
    };
    let index = lines.findIndex((i) => i.get("id") === id);
    let result = lines.update(index, updater);
    
    initialState.set("lines", result);
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

    【讨论】:

    • 看起来不错。我得到一个错误:Uncaught TypeError: k is not a function
    • 但是有人喜欢投反对票……可以接受吗?
    • 这里不是downvoter - 但是当它不需要时,你正在将一个子部分从不可变中拉出来,并且不满足 OP 请求的业务逻辑(将活动更改为 true 和 false 等。 )
    • 是的,朋友,没问题...请注意,您应该在投反对票后发表评论,而不仅仅是在请求时发表评论:这是有建设性的。我更新了几乎相同的name 道具……重要的是逻辑。对于pull out a subsection,确实如此……您可能是对的,不需要。
    • 谢谢两位。我也喜欢 Hitmands 的解决方案,因为现在我还可以找到给定项目的索引并更新它。不可变 API 确实令人困惑。不过,我决定使用 ajmajmajma 的解决方案。它要简单得多。
    猜你喜欢
    • 2021-10-03
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多