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

时间:2016-10-18 11:52:19

标签: javascript reactjs redux immutable.js

我在基于React的项目中使用Redux和Immutable.js(基于React Boilerplate构建)并且我正在寻找一种更新或添加到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。我正在查看类似的问题和可悲​​的Immutable.js文档,但我无法看到如何执行此操作:没有语法我尝试过如我所期望的那样。

3 个答案:

答案 0 :(得分:2)

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

这里需要注意的是你如何通过account财产。如果你从某个地方派生它并以Record传递,你可以通过===(或.equals())进行比较,但它似乎只是一个普通的javascript对象 - 我&# 39;稍后会假设它。

就代码而言,它将是:

// 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);

但是我个人发现它并不灵活且不一致,因为执行深度合并是非常常见的操作。

答案 1 :(得分:0)

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

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>

答案 2 :(得分:0)

不是直接答案,而是一个有关如何使用immutable.js添加到列表的示例:

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