Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a react way to store a mutable class instance objects in state?

React state shouldn't be mutated directly. But, what if the state is an instance of a class that shall be mutable with its own methods. Is there another way than having to deep-clone and re-instantiate the object with new parameters?

In General: What is the react way for a class object created in parent components to be used in subcomponents while maintaining its properties in the parent state (which is passed down via props/context)?

Sample class

class Car{
    constructor(data){
        this.data = data
    }
    changeColor = (newcolor) => this.data.color = newcolor
}

Sample Parent Component

const App = ({data}) => {
 const [car, setCar] = useState(new Car(data))
  return (
    <div>
      <CarViewer car={car} />
    </div>
  );
};

Sample Sub componeent

const CarViewer = ({car}) => {
  return (
    <div>
      The color is: {car.data.color}
    <button onClick={()=>car.changeColor("blue")}>Change color to blue </button>
    </div>
  );
};
like image 937
elMeroMero Avatar asked Feb 05 '21 11:02

elMeroMero


People also ask

Is state mutable in React?

The state is mutable in react components. To make the React applications interactive we almost use state in every react component. State is initialized with some value and based on user interaction with the application we update the state of the component at some point of time using the setState method.

Can you have an object in state React?

State can hold any kind of JavaScript value, including objects. But you shouldn't change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy.

Is state and props are mutable in React?

Props are immutable. State is mutable. 3. Props allow you to pass data from one component to other components as an argument.


1 Answers

I think what you need to do is change your mental model of storing a class inside a react state and try different model like this which is more react way:

const CarViewer = ({ carData, changeColor }) => {
  return (
    <div>
      The color is: {carData.color}
      <button onClick={() => changeColor("blue")}>Change color to blue</button>
    </div>
  );
};

const App = ({ data }) => {
  const [carData, setCarData] = useState(data);

  const changeColor = (newcolor) =>
    setCarData((data) => ({ ...data, color: newcolor }));

  return (
    <div>
      <CarViewer carData={carData} changeColor={changeColor} />
    </div>
  );
};

EDIT: based on your comment, I think what you need is a custom hook like this:


const App = ({ data }) => {
  const { carData, changeColor } = useCar(data);
  
  return (
    <div>
      <CarViewer carData={carData} changeColor={changeColor} />
    </div>
  );
};

function useCar(defaultData = {}) {
  const [carData, setCarData] = useState(defaultData);

  const changeColor = (newcolor) =>
    setCarData((data) => ({ ...data, color: newcolor }));

  return {
    carData,
    changeColor,
    //... your other methods
  };
}
like image 182
Taghi Khavari Avatar answered Oct 05 '22 23:10

Taghi Khavari