JOJU
JOJU

Reputation: 67

good way to change React JS state

{
 "user":{
  "auth":true,
  "sub_sq":[
   "1":{
    "createdAt":"2021-08-28"
   }
  ]
 },
 "sub":{
  "name":"123"
  "sub_sq":[
   "1":{
    "createdAt":"2021-08-21"
   }
  ]
 }
}

Hello When changing the state object like above

When applying changes to a user object

  1. Do I need to change the entire object after deep copying?

  2. Or do you only apply changes after deepcopy to the user object?

I like the two(2) method, so I'm applying the first (deepcopy only changed object)

but I'm not sure if that's the right way to do it, so I'm asking for advice.

Thank you

Upvotes: 1

Views: 138

Answers (2)

GalAbra
GalAbra

Reputation: 5148

In short, you should only copy the stuff you don't change in your new state value. For example:

const newState = {
  ...oldState,
  user: {
    ...oldState.user,
    auth: false,
  }
}

More generally, it's considered a better practice to split a deeply nested state object into multiple states. That allows you to be more specific in your state updates and later in your state listeners (i.e. useEffect). For example, you could split your original state value into two variables:

const [user, setUser] = useState({
  "auth": true,
  "sub_sq": [
    "1": {
      "createdAt":"2021-08-28"
    }
  ]
});
const [sub, setSub] = useState({
  "name": "123"
  "sub_sq": [
    "1": {
      "createdAt":"2021-08-21"
    }
  ]
});

If you insist on using a composite state, it's better to use a reducer to update each state "part" in a more controlled fashion. From React's useReducer documentation:

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one

Upvotes: 2

vitoke
vitoke

Reputation: 748

Indeed this is a nagging problem with state management. Using the spread operator or the suggested immer library is a good option. I myself have created the @rimbu/deep library for this. It has a method named patch that allows you to write things like:

import { patch } from '@rimbu/deep';

const person = {
  name: "Alice",
  age: 34,
  address: {
    street: "Random street",
    number: 45
  },
  friends: ["Bob", "Carol"]
};

const updatedPerson = patch(person)({
  age: v => v + 1,
  address: {
    street: "Other street"
  },
  friends: v => [...v, "Anne"]
})

// updatedPerson is now:
// {
//   name: "Alice",
//   age: 35,
//   address: {
//     street: "Other street",
//     number: 45
//   },
//   friends: ["Bob", "Carol", "Anne"]
// }

It's quite new and needs more documentation, but just wanted to share.

You can play around with this CodeSandbox:

Edit rimbu-sandbox

Upvotes: 0

Related Questions