[英]React setState of for deeply nested value
I've got a very deeply nested object in my React state.我的 React 状态中有一个非常深的嵌套对象。 The aim is to change a value from a child node.
目的是更改子节点的值。 The path to what node should be updated is already solved, and I use helper variables to access this path within my setState.
应该更新哪个节点的路径已经解决了,我使用辅助变量在我的 setState 中访问这个路径。
Anyway, I really struggle to do setState within this nested beast.无论如何,我真的很难在这个嵌套的野兽中执行 setState 。 I abstracted this problem in a codepen: https://codesandbox.io/s/dazzling-villani-ddci9
我在代码笔中抽象了这个问题: https ://codesandbox.io/s/dazzling-villani-ddci9
In this example I want to change the child's changed
property of the child having the id
def1234
.在此示例中,我想更改具有
id
def1234
的孩子的孩子的changed
属性。
As mentioned the path is given: Fixed Path values: Members, skills
and variable Path values: Unique Key 1
(coming from const currentGroupKey
and both Array position in the data coming from const path
如前所述,给出了路径:固定路径值:
Members, skills
和变量路径值: Unique Key 1
(来自const currentGroupKey
和来自const path
的数据中的两个数组位置
This is my state object:这是我的状态对象:
constructor(props) {
super(props);
this.state = {
group:
{
"Unique Key 1": {
"Members": [
{
"name": "Jack",
"id": "1234",
"skills": [
{
"name": "programming",
"id": "13371234",
"changed": "2019-08-28T19:25:46+02:00"
},
{
"name": "writing",
"id": "abc1234",
"changed": "2019-08-28T19:25:46+02:00"
}
]
},
{
"name": "Black",
"id": "5678",
"skills": [
{
"name": "programming",
"id": "14771234",
"changed": "2019-08-28T19:25:46+02:00"
},
{
"name": "writing",
"id": "def1234",
"changed": "2019-08-28T19:25:46+02:00"
}
]
}
]
}
}
};
}
handleClick = () => {
const currentGroupKey = 'Unique Key 1';
const path = [1, 1];
// full path: [currentGroupKey, 'Members', path[0], 'skills', path[1]]
// result in: { name: "writing", id: "def1234", changed: "2019-08-28T19:25:46+02:00" }
// so far my approach (not working) also its objects only should be [] for arrays
this.setState(prevState => ({
group: {
...prevState.group,
[currentGroupKey]: {
...prevState.group[currentGroupKey],
Members: {
...prevState.group[currentGroupKey].Members,
[path[0]]: {
...prevState.group[currentGroupKey].Members[path[0]],
skills: {
...prevState.group[currentGroupKey].Members[path[0]].skills,
[path[1]]: {
...prevState.group[currentGroupKey].Members[path[0]].skills[
path[1]
],
changed: 'just now',
},
},
},
},
},
},
}));
};
render() {
return (
<div>
<p>{this.state.group}</p>
<button onClick={this.handleClick}>Change Time</button>
</div>
);
}
I would appreciate any help.我将不胜感激任何帮助。 I'm in struggle for 2 days already :/
我已经挣扎了 2 天了:/
Before using new dependencies and having to learn them you could write a helper function to deal with updating deeply nested values.在使用新的依赖项和学习它们之前,您可以编写一个辅助函数来处理更新深层嵌套的值。
I use the following helper:我使用以下助手:
//helper to safely get properties // get({hi},['hi','doesNotExist'],defaultValue) const get = (object, path, defaultValue) => { const recur = (object, path) => { if (object === undefined) { return defaultValue; } if (path.length === 0) { return object; } return recur(object[path[0]], path.slice(1)); }; return recur(object, path); }; //returns new state passing get(state,statePath) to modifier const reduceStatePath = ( state, statePath, modifier ) => { const recur = (result, path) => { const key = path[0]; if (path.length === 0) { return modifier(get(state, statePath)); } return Array.isArray(result) ? result.map((item, index) => index === Number(key) ? recur(item, path.slice(1)) : item ) : { ...result, [key]: recur(result[key], path.slice(1)), }; }; const newState = recur(state, statePath); return get(state, statePath) === get(newState, statePath) ? state : newState; }; //use example const state = { one: [ { two: 22 }, { three: { four: 22, }, }, ], }; const newState = reduceStatePath( state, //pass state.one[1],three.four to modifier function ['one', 1, 'three', 'four'], //gets state.one[1].three.four and sets it in the //new state with the return value i => i + 1 // add one to state.one[0].three.four ); console.log('new state', newState.one[1].three.four); console.log('old state', state.one[1].three.four); console.log( 'other keys are same:', state.one[0] === newState.one[0] );
If you need to update a deeply nested property inside of your state, you could use something like the set
function from lodash
, for example:如果您需要更新状态内部的深层嵌套属性,您可以使用
lodash
的set
函数之类的东西,例如:
import set from 'lodash/set'
// ...
handleClick = () => {
const currentGroupKey = 'Unique Key';
const path = [1, 1];
let nextState = {...this.state}
// as rightly pointed by @HMR in the comments,
// use an array instead of string interpolation
// for a safer approach
set(
nextState,
["group", currentGroupKey, "Members", path[0], "skills", path[1], "changed"],
"just now"
);
this.setState(nextState)
}
This does the trick, but since set
mutates the original object, make sure to make a copy with the object spread
technique.这可以解决问题,但由于
set
改变原始对象,因此请确保使用object spread
技术进行复制。
Also, in your CodeSandbox
example, you set the group
property inside of your state
to a string.此外,在您的
CodeSandbox
示例中,您将state
内的group
属性设置为字符串。 Make sure you take that JSON
string and construct a proper JavaScript object with it so that you can use it in your state.确保您使用该
JSON
字符串并用它构建一个合适的 JavaScript 对象,以便您可以在您的状态下使用它。
constructor(props) {
super(props)
this.setState = { group: JSON.parse(myState) }
}
Here's a working example:这是一个工作示例:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.