当使用时,immutable.js几乎已经成为一个行业标准。我的问题是,当我们使用扩展运算符时,我们不是在不断地修改我们的redux状态吗?例如,
const reducer = (state=initialState, action) => {
switch(action.type){
case actionType.SOME_ACTION:
return {
...state,
someState: state.someState.filter(etc=>etc)
}
}难道我用redux不可变的方式来设置状态吗?使用immutable.js operator使对象不可变的好处是什么?
如果有人问了这个问题,我很抱歉,但我找不到满意的答案。我理解不可变对象的好处,但不理解使用immutable.js库而不是点运算符的重要性。
发布于 2018-11-22 21:05:01
简短回答
是!ES6扩展操作符可以完全用作immutable.js的替代品,但是有一个重要的警告,您必须在任何时候都保持对情况的了解。
很长的答案
您和您的其他开发人员将百分之百地负责维护不变性,而不是让immutable.js来照顾您。这里详细介绍了如何使用ES6‘like运算符’以及它的各种函数(如filter和map )来管理不可变的状态。
下面将探索如何以不可变和可变的方式将值移除并添加到数组或对象。我在每个示例中注销了initialState和newState,以演示我们是否已经变异了initialState。这很重要,因为如果initialState和newState完全相同,Redux就不会指示UI重新呈现。
注意:如果您尝试了以下任何一种不同的解决方案, Immutable.js都会使应用程序崩溃。
从数组中删除元素
不变方式
const initialState = {
members: ['Pete', 'Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
return {
...state,
members: state.members.filter(
member => member !== action.member
)
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'Pete'}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: ['Pete', 'Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
state.members.forEach((member, i) => {
if (member === action.member) {
state.members.splice(i, 1)
}
})
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'Pete'}
);
console.log('initialState', initialState);
console.log('newState', newState);
将元素添加到数组
不变方式
const initialState = {
members: ['Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'ADD_MEMBER':
return {
...state,
members: [...state.members, action.member]
}
}
}
const newState = reducer(
initialState,
{type: 'ADD_MEMBER', member: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: ['Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'ADD_MEMBER':
state.members.push(action.member);
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'ADD_MEMBER', member: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
更新阵列
不变方式
const initialState = {
members: ['Paul', 'Pete', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'UPDATE_MEMBER':
return {
...state,
members: state.members.map(member => member === action.member ? action.replacement : member)
}
}
}
const newState = reducer(
initialState,
{type: 'UPDATE_MEMBER', member: 'Pete', replacement: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: ['Paul', 'Pete', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'UPDATE_MEMBER':
state.members.forEach((member, i) => {
if (member === action.member) {
state.members[i] = action.replacement;
}
})
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'UPDATE_MEMBER', member: 'Pete', replacement: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
合并阵列
不变方式
const initialState = {
members: ['Paul', 'Ringo']
}
const reducer = (state, action) => {
switch(action.type){
case 'MERGE_MEMBERS':
return {
...state,
members: [...state.members, ...action.members]
}
}
}
const newState = reducer(
initialState,
{type: 'MERGE_MEMBERS', members: ['George', 'John']}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: ['Paul', 'Ringo']
}
const reducer = (state, action) => {
switch(action.type){
case 'MERGE_MEMBERS':
action.members.forEach(member => state.members.push(member))
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'MERGE_MEMBERS', members: ['George', 'John']}
);
console.log('initialState', initialState);
console.log('newState', newState);
对经验丰富的开发人员来说,上面的数组变异示例似乎是一个明显的不良实践,但对于新开发人员来说,这是一个很容易的陷阱。我们希望任何变异的代码片段都会被捕获到代码评审中,但情况并不总是如此。让我们来谈谈对象,这些对象在自己处理不可变性时更麻烦。
从对象中移除
不变方式
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
stuart: {
name: 'Stuart',
instrument: 'Bass'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
let { [action.member]: _, ...members } = state.members
return {
...state,
members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'stuart'}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
stuart: {
name: 'Stuart',
instrument: 'Bass'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
delete state.members[action.member]
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'stuart'}
);
console.log('initialState', initialState);
console.log('newState', newState);
更新对象
不变方式
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'CHANGE_INSTRUMENT':
return {
...state,
members: {
...state.members,
[action.key]: {
...state.members[action.member],
instrument: action.instrument
}
}
}
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);
突变方式
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'CHANGE_INSTRUMENT':
state.members[action.member].instrument = action.instrument
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);
如果你成功了,恭喜你!我知道这是一个冗长的帖子,但我觉得重要的是展示所有变异的方式,,您需要防止自己没有Immutable.js。除了防止您编写糟糕的代码之外,使用Immutable.js的一个巨大优势是助手方法,如mergeDeep和updateIn。
Immutable.JS
mergeDeep
const initialState = Immutable.fromJS({
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
})
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_MEMBERS':
return state.mergeDeep({members: action.members})
}
}
const newState = reducer(
initialState,
{
type: 'ADD_MEMBERS',
members: {
george: { name: 'George', instrument: 'Guitar' },
john: { name: 'John', instrument: 'Guitar' }
}
}
);
console.log('initialState', initialState);
console.log('newState', newState);<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>
updateIn
const initialState = Immutable.fromJS({
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
})
const reducer = (state, action) => {
switch (action.type) {
case 'CHANGE_INSTRUMENT':
return state.updateIn(['members', action.member, 'instrument'], instrument => action.instrument)
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>
https://stackoverflow.com/questions/53437937
复制相似问题