Home > Mobile >  Why is the assigned object not being written too?
Why is the assigned object not being written too?

Time:01-23

I have a recoil state that is an object that is structured like this:

const Proposal = atom({
  key: "PROPOSAL",
  scopes: [{
    assemblies: [{
      items: [{}]
    }]
  }]
})

When theres updates to an item in the UI I am updating the atom by mapping through scopes, assemblies and items. When I find the correct item I am updating I am logging the current item, then logging the updated item. These logs are correct so I can see the value being updated. But when I get to the third log it does not show the updated value.

const [proposal, setProposal] = useRecoilState(Proposal)

const applyUpdatesToProposalObj = useCallback(_.debounce(params => {setProposal(proposal => {
  setProposal(proposal => {
    let mutable = Object.assign({}, proposal);

    for(let i = 0; i < mutable.scopes.length; i  ) {
      let scope = mutable.scopes[i]

      for(let j = 0; j < scope.assemblies.length; j  ) {
        let assembly = scope.assemblies[j]

        for(let k = 0; k < assembly.items.length; k  ) {
          let item = assembly.items[k]

          if(item._id === id) {
            console.log('1', item)
            item = {
              ...item,
              ...params
            }
            console.log('2', item)
          }
        }
      }
    }

    console.log('3', mutable)

    return mutable
 })
}, 350), [])

The output of the logs look like this:

1 { ...item data, taxable: false }
2 { ...item data, taxable: true }
3 { scopes: [{ assemblies: [{ items: [{ ...item data, taxable: false }] }] }] } 

I setup a sandbox where you can view the behavior https://codesandbox.io/s/young-dew-w0ick?file=/src/App.js

Another odd thing is I have an object inside the proposal called changes. I setup an atom for the changes object and update it in a similar fashion and that is working as expected.

CodePudding user response:

Extending on the little conversation we had in the comments: you'd have to clone the entire tree of objects you want to mutate, also in a proper way. This is quite tedious to do in plain javascript, so at the cost of a little performance (this example is updating all arrays along the way), this can be optimized to somewhat more readable:

setProposal((proposal) => {
    let mutable = proposal;
    console.log("before", mutable);

    mutable = {
      ...mutable,
      scopes: mutable.scopes.map((scope) => ({
        ...scope,
        assemblies: scope.assemblies.map((assembly) => ({
          ...assembly,
          items: assembly.items.map((item) => {
            if (item.id === id) {
              return {
                ...item,
                ...params
              };
            } else {
              return item;
            }
          })
        }))
      }))
    };

    console.log("after", mutable);

    return mutable;
  });
  •  Tags:  
  • Related