[英]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。 我正在查看类似的问题和可悲的Immutable.js文档,我无法看到如何做到这一点:我尝试的语法没有像我期望的那样工作。
那么,你需要的是嵌套更新。 首先,您必须检查您已加载的帐户列表是否有此帐户。 其次,您必须更改activeAccount
字段。 最后,将帐户添加(或更新)到loadedAccounts
。
这里需要注意的是你如何通过account
财产。 如果你从某个地方派生它并作为Record
传递,你可以通过===
(或.equals())进行比较,但它似乎只是一个简单的javascript对象 - 我会在以后想到它。
在代码方面,它将是这样的:
// 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);
但我个人发现它并不灵活且不一致,因为执行深度合并是非常常见的操作。
我希望这个例子有所帮助,我正在创建一个新的不可变列表,并首先执行更新,然后添加一个新元素。 我没有传递我想要替换的对象,但是你也可以传递你现有的对象,同样在更新方法中你可以访问当前项目
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>
不是直接的答案,而是如何使用immutable.js添加到列表的示例:
let oldList = List([ 1, 2, 3, 4 ])
let newList = oldList.push(5)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.