如何更新或添加到 immutable.js 列表

How to update or add to immutable.js List

我在基于 React 的项目(基于 React Boilerplate)中使用 Redux 和 Immutable.js,我正在寻找一种惯用的方式来更新或添加到 Immutable.js 列表.

我目前的设置。状态最初看起来像这样:

const initialState = fromJS({
  accounts: [],
  activeAccount: null,
  loadedAccounts: [],
});

我有一个 account 对象的不可变记录:

const account = new Record({
  description: '',
  id: '',
  name: '',
  status: '',
});

还有我的减速器:

function reducer(state = initialState, action) {
  switch (action.type) {
    case LOAD_ACCOUNT_SUCCESS:
      return state
        .set('activeAccount', new account(action.account))
    default:
      return state;
  }
}

这工作正常 - 当触发 LOAD_ACCOUNT_SUCCESS 操作时,activeAccount 更新为 action.account 的值。

我可以对此进行修改,以便每个新的 LOAD_ACCOUNT_SUCCESS 操作都将新加载的帐户数据推送到 loadedAccounts

function reducer(state = initialState, action) {
  switch (action.type) {
    case LOAD_ACCOUNT_SUCCESS:
      const loadedAccount = new account(action.account);
        return state
          .update('loadedAccounts', (loadedAccounts) => loadedAccounts.push(loadedAccount));
    default:
      return state;
  }
}

但是,目前两次加载相同的帐户数据将导致每次都将新记录推送到我的列表(重复数据)。我想做的是 或者action.account 添加到 loadedAccounts (就像现在发生的那样) 更新记录如果有匹配的 ID,则为 List。我正在查看类似的问题和可悲​​的 Immutable.js 文档,但我不知道该怎么做:我在这里尝试过的语法都没有像我期望的那样工作。

我希望这个例子能有所帮助,我正在创建一个新的不可变列表并首先执行更新,然后添加一个新元素。我没有传递我想要替换的对象,但你也可以传递你现有的对象,同样在更新方法中你可以访问当前项目

class Test {
  a = null;
  b = null;
 constructor(a,b){
 this.a=a;
 this.b=b;
 }
}

$("#test").html("");

function logme(item){
  $("#test").append("<br/>"+JSON.stringify(item));
 }
function logmeNewLine(){
  $("#test").append("<br/>");
 }

function listAddUpadte(key){ 
  
     var index= list.get('data').findIndex(listing => {
    return listing.a === key;
  });
  
  logme(' found index (-1 for not found) : ' + index);
  
  if(index >= 0){
    logme("upadte");
    list = list.set("data",list.get("data").update(index,function(item){
    return new Test(key,"go");
    }));
  }else {
    
    logme("add");
    list = list.set("data",list.get("data").push(new Test(key,"go")));
  }

  list.get('data').forEach(item=>{
    logme(item);
  });
}


var list = Immutable.fromJS({
"data":[new Test(6,"abhi"),new Test(4,"raj"),new Test(1,"ajay")]
});

logme("intial data");
list.get('data').forEach(item=>{
  
logme(item);
  
});




logmeNewLine();
logme("testing replace with a =  4 ")
logmeNewLine();
listAddUpadte(4);


logmeNewLine();
logme("testing add with a = 8 ")
logmeNewLine();
listAddUpadte(8);
logmeNewLine();
logmeNewLine();
logmeNewLine();
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.2/immutable.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>

所以,这里你需要的是嵌套更新。 首先,您必须检查您的 loadedAccounts 列表是否有此帐户。 其次,您必须更改 activeAccount 字段。 最后,将帐户添加(或更新)到 loadedAccounts

这里的警告是你如何通过 account 属性。如果你从某个地方派生它并作为 Record 传递,你可以通过 ===(或 .equals())进行比较,但它似乎只是一个普通的 javascript object – 稍后再假设。

就代码而言,它类似于:

// we can do it by different ways, it is just one of them
const listWithLoadedAccounts = state.get('loadedAccounts');
const isAccountAlready = Boolean(
  listWithLoadedAccounts.filter(
    account => account.get('id') === action.account.id
  ).size
);

const patchedState = state.set('activeAccount', action.account.id);
return isAccountAlready
  ? patchedState.updateIn(['loadedAccounts'], list => list.map(account => account.get('id') === account.action.id ? new account(action.account) : account))
  : patchedState.updateIn(['loadedAccounts'], list => list.concat(new account(action.account)))

这不是理想的代码,有些东西可以去重,但你明白了——如果你需要更改嵌套字段或数据结构,请始终使用深度合并/更新。

您也可以直接设置新字段,例如:

const oldList = state.get('loadedAccounts');
const newList = oldList.concat(action.account);
const patchedState = state.set('loadedAccounts', newList);

但我个人觉得不是那么灵活,也不一致,因为执行深度合并是很常见的操作。

因为这是问题标题内容的最高搜索结果

如何使用 immutable.js 添加到列表的示例:

let oldList = List([ 1, 2, 3, 4 ])
let newList = oldList.push(5)

insert()

Returns a new List with value at index with a size 1 more than this List. Values at indices above index are shifted over by 1. insert(index: number, value: T): List Discussion

This is synonymous with list.splice(index, 0, value).

List([ 0, 1, 2, 3, 4 ]).insert(6, 5)
// List [ 0, 1, 2, 3, 4, 5 ]