michi07
michi07

Reputation: 105

Store auto-updating object inside React state

I have this situation but I don't know if it's ok to do something like this. If I save an object inside the state of my component, can the object modify itself without using setState?

File A.js

export default class A {
    constructor(value) {
        this.value = value;
    }

    setValue(value) {
        this.value = value;
    }
}

File B_Component.js

import React from "react";
import A from "./A";

class B_Component extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            aObj = new A("foo")
        }
    }

    bar = () => {
        this.state.aObj.setValue("bar");
    }

    ...render etc...
}

Basically this should modify the state of the component without using setState. Is this correct or there may be problems?

Upvotes: 2

Views: 381

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

Is this correct or there may be problems?

There may be problems. :-) If you're rendering that object's value, then you're breaking one of the fundamental rules of React, which is that you can't directly modify state. If you do, the component won't re-render.

Instead, you create a new object and save the new object in state:

bar = () => {
    this.setState({aObj: new A("bar")});
}

Or if you want to reuse other aspects of the object and only change value:

bar = () => {
    const aObj = new A(this.state.aObj); // Where this constructor copies all the 
                                         // relevant properties
    aObj.setValue("bar");
    this.setState({aObj});
}

The A constructor would be

constructor(other) {
    this.value = other.value;
    // ...repeat for any other properties...
}

Or you might give A a new function, withValue, that creates a new A instance with an updated value:

class A {
    constructor(value) {
        this.value = value;
        // ...other stuff...
    }

    withValue(value) {
        const a = new A(value);
        // ...copy any other stuff to `a`...
        return a;
    }
}

Then:

bar = () => {
    this.setState({aObj: this.state.aObj.withValue("bar")});
}

Upvotes: 2

Related Questions