如何在ReactJS中使用reduce函数处理嵌套状态对象?

3

我的状态值是

this.state = {
    content: {
        text: {
            tag1: {
                line: "data1"
            }
            tag2: {
                line: "data2"
            }
        }
    }
}

如何使用JavaScript的reduce()函数将tag1tag2line值更改为"更改后的文本"


1
你为什么要使用.reduce()来做这件事呢? - Nicolae Maties
1
.reduce出于很多原因不适合这个目的,其中第一个原因是它的目标是减少初始项并且旨在处理数组,而您需要改变一个对象。只需在对象键上使用常规的for..in或.forEach即可。 - briosheje
4个回答

1

您应该使用函数调用setState,而不是直接更改state

this.setState(prevState => {        
    for(let k in prevState.content.text){
        prevState.content.text[k].line = "changed";
    } 
    return {content: prevState.content}
}

编辑:

我不确定直接更改prevState是否是一个好的做法(请有经验的人纠正我),但你也可以这样做:

this.setState(prevState => {   
    let changedState = {...prevState}     
    for(let k in changedState.content.text){
        changedState.content.text[k].line = "changed";
    } 
    return {content: changedState.content}
}

编辑:

正如评论中所说,{...prevState} 将是一个浅拷贝,它仍然可以直接更改状态。解决此问题的一种方法是使用 lodash cloneDeep


2
"{...prevState}" 不会解决问题,因为它只是浅拷贝。 - georg

1

在这里:

this.setState(prevState => {
    return {
        content: {
            ...prevState.content,
            text: Object.keys(prevState.content.text).reduce((newTexts, key) => {
                return {
                    ...newTexts,
                    [key]: {
                        line: "changed text"
                    }
                }
            }, {})
        }
    }
});

0

我认为使用 for..in 会更好。

const state = {
    content: {
        text: {
            tag1: {
                line: "data1"
            },
            tag2: {
                line: "data2"
            }
        }
    }
}

for(let k in state.content.text){
  state.content.text[k].line = "changed";
} 
console.log(state)


1
这不是一个好的答案,因为在React中,你不应该直接改变状态(state),而应该使用 setState - Vencovsky
1
在 React 状态的上下文中,这个答案没有意义,因为你正在改变状态。 - dashton

0

我认为Array#prototype#reduce不太适合。

你可以使用一个简单的现代for...of循环,结合Object.entries来实现:

const state = {
    content: {
        text: {
            tag1: {
                line: "data1"
            },
            tag2: {
                line: "data2"
            }
        }
    }
};

for (const obj of Object.entries(state.content.text)) {
 obj[1].line = 'Changed text';
}

console.log(state);


为了实现不可变状态,您可以在修改新对象的属性之前使用{{link1:Object.assign}}。

const state = {
  content: {
    text: {
      tag1: {
        line: "data1"
      },
      tag2: {
        line: "data2"
      }
    }
  }
};

// Create a new object from an existing object
const newState = Object.assign(state, {});

Object.entries(newState.content.text).forEach(x => {
  x[1].line = 'Changed text';
});

console.log(newState);


2
这不是一个好的答案,因为在React中,你不应该直接改变状态,而应该使用 setState - Vencovsky
1
你没有使用React的setState。你的答案在逻辑上是正确的,但是因为它不在React的上下文中,所以是错误的。 - Vencovsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接