我是immutablejs的新手,并且设法更新了存储在对象数组中的对象的属性。我的目标是简化我的开发,但是我觉得自己变得更加复杂。显然,我缺少使它更简单的东西。
我创建了要堆叠的项目,一个使用不带有immutablejs https://stackblitz.com/edit/react-before-immutable的代码,另一个使用不可变的https://stackblitz.com/edit/react-after-immutable代码
(下面的代码也是如此)。
我在这里看到了一些示例,其中人们使用findIndex的第二个参数,但是从未为我调用过该函数。它也不在文档中,所以我猜它不再受支持。
使用Immutable.js
import React, { useState } from 'react';
import { List } from 'immutable';
export default () => {
const init = [{
id: 101,
interestLevel: 1
},
{
id: 102,
interestLevel: 0
}];
const [myArray, setMyArray] = useState(init);
const updateRow = (e) => {
const id = parseInt(e.target.attributes['data-id'].value);
const immutableMyArray = List(myArray);
const index = List(myArray).findIndex((item) => {
return item.id === id;
});
const myRow = immutableMyArray.get(index);
myRow.interestLevel++;
const newArray = immutableMyArray.set(index, myRow);
setMyArray(newArray);
};
return (
<ul>
{
myArray.map(function (val) {
return (
<li key={val.id}>
<button onClick={updateRow} data-id={val.id} >Update Title</button>
{val.id} : {val.interestLevel}
</li>
)
})
}
</ul>
)
}
没有Immutable.js
import React, { useState } from 'react';
export default () => {
const init = [{
id: 101,
interestLevel: 1
},
{
id: 102,
interestLevel: 0
}];
const [myArray, setMyArray] = useState(init);
const updateRow = (e) => {
const id = e.target.attributes['data-id'].value;
const newMyArray = [...myArray];
var index = newMyArray.findIndex(a=>a.id==id);
newMyArray[index].interestLevel = myArray[index].interestLevel + 1;
setMyArray(newMyArray);
}
return (
<ul>
{
myArray.map(function (val) {
return (
<li key={val.id}>
<button onClick={updateRow} data-id={val.id} >Update Title</button>
{val.id} : {val.interestLevel}
</li>
)
})
}
</ul>
)
}
答案 0 :(得分:0)
您是否考虑过immutablejs的目的?
在您的示例中,您仅在代码中增加了不必要的复杂性,而没有利用库提供的收益。
不可变的目的是提供受scala启发的不可变集合。换句话说,创建集合,然后将其传递到另一个组件,可以确定没有添加或删除任何元素。但是,单个元素不受此保证,部分原因是JS带来的约束(或缺乏约束)。
正如您代码中所代表的那样,很少有理由要做这样的事情。为了说明如何更改,我已经大胆地更改了您的报价:
class Comp extends React.Component {
constructor(props) {
super(constructor);
if (props.interests) {
this.state = {
interests: props.interests
}
} else {
this.state = {
interests: Immutable.Set([])
}
}
}
updateRow(e) {
return function() {
this.setState({
interests: this.state.interests.update((elements) => {
for (var element of elements) {
if (element.id == e) {
element.interestLevel++;
}
}
return elements;
})
});
}
}
render() {
var interests = this.state.interests;
var updateRow = this.updateRow;
var list = this;
//return (<div>Test</div>);
return ( <
ul > {
interests.map(function(val) {
return ( <
li key = {
val.id
} >
<
button onClick = {
updateRow(val.id).bind(list)
}
data-id = {
val.id
} > Update Title < /button> {
val.id
}: {
val.interestLevel
} <
/li>
)
})
} <
/ul>
)
}
}
var interests = Immutable.Set([{
id: 1,
interestLevel: 0
},
{
id: 2,
interestLevel: 0
}
])
ReactDOM.render( < Comp interests = {
interests
}
/>, document.getElementById("app"));
<script src="https://cdn.jsdelivr.net/npm/immutable@4.0.0-rc.12/dist/immutable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0/umd/react-dom.production.min.js"></script>
<div id='app'></div>
更改:
prop
。这意味着您可以传递Set
并确保它不会在组件中添加蓝色的元素update
上调用Set
函数,该函数用于更新集合中的项目render()
呈现为数组这既可读性强又易于管理。
答案 1 :(得分:0)
如本comment中所述,您正在寻找使用Immutable.js在深层对象层次结构中更新对象的简便方法。
updateIn应该可以解决问题。
const immutableObject = Immutable.fromJS({ outerProp: { innerCount: 1 } });
immutableObject.updateIn(['outerProp', 'innerCount'], count => count + 1);
还值得注意的是,您可能想调用Immutable.fromJS()
而不是使用Immutable.List()
,因为后者不会将您的JavaScript对象深深地转换为不可变对象,如果您使用重新假设数据结构是完全不变的。将上面的代码切换为使用Immutable.fromJS()
和updateIn
,我们得到:
// In updateRow
const immutableMyArray = fromJS(myArray);
const index = immutableMyArray.findIndex((item) => {
return item.id === id;
});
const newArray = immutableMyArray.updateIn([index, 'interestLevel'], interestLevel => interestLevel + 1);
setMyArray(newArray);