存储处于 React 组件状态的对象?

是否可以将对象存储在 React 组件的状态中?如果是,那么我们如何使用 setState更改该对象中键的值?我认为在句法上不允许这样写:

this.setState({ abc.xyz: 'new value' });

在类似的行中,我还有另一个问题: 在 React 组件中有一组变量可以用于组件的任何方法,而不是将它们存储在一个状态中,这样可以吗?

您可以创建一个包含所有这些变量的简单对象,并将其放置在组件级别,就像在组件上声明任何方法一样。

它很可能遇到这样的情况,即在代码中包含大量业务逻辑,并且需要使用许多变量,这些变量的值通过多种方法进行更改,然后根据这些值更改组件的状态。

因此,与保持所有这些变量的状态不同,您只保留那些其值应该直接反映在 UI 中的变量。

如果这种方法比我在这里写的第一个问题更好,那么我就不需要在状态中存储对象。

145814 次浏览
  1. this.setState({ abc.xyz: 'new value' }); syntax is not allowed. You have to pass the whole object.

    this.setState({abc: {xyz: 'new value'}});
    

    If you have other variables in abc

    var abc = this.state.abc;
    abc.xyz = 'new value';
    this.setState({abc: abc});
    
  2. You can have ordinary variables, if they don't rely on this.props and this.state.

In addition to kiran's post, there's the update helper (formerly a react addon). This can be installed with npm using npm install immutability-helper

import update from 'immutability-helper';


var abc = update(this.state.abc, {
xyz: {$set: 'foo'}
});


this.setState({abc: abc});

This creates a new object with the updated value, and other properties stay the same. This is more useful when you need to do things like push onto an array, and set some other value at the same time. Some people use it everywhere because it provides immutability.

If you do this, you can have the following to make up for the performance of

shouldComponentUpdate: function(nextProps, nextState){
return this.state.abc !== nextState.abc;
// and compare any props that might cause an update
}

this.setState({abc: {xyz: 'new value'}}); will NOT work, as state.abc will be entirely overwritten, not merged.

This works for me:

this.setState((previousState) => {
previousState.abc.xyz = 'blurg';
return previousState;
});

Unless I'm reading the docs wrong, Facebook recommends the above format. https://facebook.github.io/react/docs/component-api.html

Additionally, I guess the most direct way without mutating state is to directly copy by using the ES6 spread/rest operator:

const newState = { ...this.state.abc }; // deconstruct state.abc into a new object-- effectively making a copy
newState.xyz = 'blurg';
this.setState(newState);

Even though it can be done via immutability-helper or similar I do not wan't to add external dependencies to my code unless I really have to. When I need to do it I use Object.assign. Code:

this.setState({ abc : Object.assign({}, this.state.abc , {xyz: 'new value'})})

Can be used on HTML Event Attributes as well, example:

onChange={e => this.setState({ abc : Object.assign({}, this.state.abc, {xyz : 'new value'})})}

You can use ES6 spread on previous values in the object to avoid overwrite

this.setState({
abc: {
...this.state.abc,
xyz: 'new value'
}
});

Easier way to do it in one line of code

this.setState({ object: { ...this.state.object, objectVarToChange: newData } })

If you want to store an object in the state using functional components you can try the following.

import React from 'react';
import {useState, useEffect} from 'react';


const ObjectState= () => {
const [username, setUsername] =  useState({});


const usernameSet = () => {
const name = {
firstname: 'Naruto',
familyname: 'Uzmaki'
}
setUsername(prevState => name);
}


return(
<React.Fragment>
<button onClick= {usernameSet}>
Store Object
</button>
{username.firstname} {username.familyname}
</React.Fragment>
)
}


export default ObjectState;

If you want to add an object to a pre-existing object.

import React from 'react';
import {useState, useEffect} from 'react';


const ObjectState= () => {
const [username, setUsername] =  useState({village: 'Konoha'});


const usernameSet = () => {
setUsername((prevState) => {
const data = {
...prevState,
firstname: 'Naruto',
familyname: 'Uzmaki'
}
return data
});
}


return(
<React.Fragment>
<button onClick= {usernameSet}>
Store Object
</button>
{username.village} {username.firstname} {username.familyname}
</React.Fragment>
)
}


export default ObjectState;

P.S. : Naming the component 'Object' leads to an 'Maximum call stack size exceeded error'. Other names are fine but for some reason 'Object' is not. Like the following is not ok.

    const Object = () => {
// The above code
};


export default Object;

If anyone knows why or how to prevent it please add it to the comments.