pmndrs / valtio

🧙 Valtio makes proxy-state simple for React and Vanilla
https://valtio.dev
MIT License
9.08k stars 252 forks source link

[Question] Updating multiple state object values at once #31

Closed xzilja closed 3 years ago

xzilja commented 3 years ago

I came across interesting behaviour today, here is example of a dialog state that I have with some actions

let dialogState = proxy({
  open: false,
  data: undefined,
  direction: 'bottom-top'
})

function showDialog(open, direction, data) {
    dialogState.open = true;
    dialogState.data = data;
    dialogState.direction = direction;
}

Updating dialog state values this way re renders my react component (that subscribes to all 3 values) 3 times, which is relatively intuitive as I am updating my state 3 times. So I refactored my action to update whole state at once

function showDialog(open, direction, data) {
    dialogState = {
      ...dialogState,
      open,
      data,
      direction
    }
}

but this way it doesn't trigger any updates on react component, so I assume I am missing something? Is there a way to update multiple state values at once in order to consolidate re-rendering calls in react components that use useProxy?

Aslemammad commented 3 years ago

@IljaDaderko Thanks for your report, first of all, your second showDialog example won't work, because the proxies won't trigger the change of the whole proxy. For better discussion, Could you make a codesandbox?

@dai-shi

xzilja commented 3 years ago

Created codesanbox https://codesandbox.io/s/empty-sun-rufhc?file=/src/App.js however I am not able to see anything weird with rendering in this simple example, so I might be doing something wrong on my end. Will re-open this issue if I find anything related to valtio.

Aslemammad commented 3 years ago

@IljaDaderko I didn't see anything weird too.

dai-shi commented 3 years ago

Thanks @Aslemammad

@IljaDaderko This 👇 won't work because we throw away the proxy.

let state = proxy({ a: 1 })
state = { a: 2 }

However, this works. 👇

const state = proxy({ obj: { a: 1 } })
state.obj = { a: 2 }

Like magic? If you have an idea to improve documentation to reduce the confusion, it's worth considering.

btw,

    dialogState.open = true;
    dialogState.data = data;
    dialogState.direction = direction;

☝️ This should work fine since v0.4.0. It only re-renders once.

AjaxSolutions commented 3 years ago

@dai-shi I'm curious how does valtio know that these state changes should be batched?

dai-shi commented 3 years ago

It just invokes callback async. (We had some discussions in the discord channel.) https://github.com/pmndrs/valtio/blob/a0b772503582b287e1fe0b23d2150482931d4795/src/vanilla.ts#L168