DEV Community

loading...

Feature request: [state,,updateState] = useState(...)

ipavlenko profile image Igor Pavlenko ・1 min read

Simple update state pattern:

const [state, setState] = useState({
  isBusy = false,
  error = null,
  data = null
})

const updateState = (newState) => setState(
  (prevState) => ({
    ...prevState,
    ...newState,
  })
)

How about making updateState a default third value in useState response?

E.g.:

const [state,, updateState] = useState({
  isBusy = false,
  error = null,
  data = null
})

const init = () => {
  if (!state.isBusy) {
    updateState({ isBusy: true, error: null })
    setImmediate(
      async () => {
        try {
          const data = await fetch(...)
          updateState({ isBusy: false, data })
        } catch (e) {
          updateState({ isBusy: false, error: e })
        }
      }
    )
  }
}

Discussion (10)

pic
Editor guide
Collapse
stojakovic99 profile image
Nikola Stojaković • Edited

I don't quite see the point of having this. setState method already updates the state. Also, I think you should actually split your object in three useState hook calls. To be honest, I'm still learning about Hooks API but that's what I understand so far by seeing examples of hooks usage.

Collapse
ipavlenko profile image
Igor Pavlenko Author

There is no batching for setState calls yet. My suggestion may solve this problem.

Collapse
benvds profile image
Ben van de Sande

I think it is not added because this is "standard" merge function and out of scope of react as a rendering library. It is easily written yourself and a lot of utility libraries like lodash also include this function.

The recommended way for splitting state variables is: "...split state into multiple state variables based on which values tend to change together." - reactjs.org/docs/hooks-faq.html#sh...

I think this is because every state change triggers a render. Therefore you probably also see { loading, data, error } variables combined; because they are mostly updated together.

Collapse
wozzo profile image
Warren

Since hooks I've been splitting these up in to separate useState calls (one for each property). Is there an advantage of keeping it in a single object?

Collapse
ipavlenko profile image
Igor Pavlenko Author

You are right, better example is required here.
P.S. Example updated, thanks

Collapse
wozzo profile image
Warren • Edited

I see. You could achieve this with a custom hook.
Something like (am on phone so forgive mistakes please) :

function useObjectState(object initial) {
    const [ value, setValue] = useState(initial) 
    const updateState = (object newState) => setState({...value, ...newState}) 
    return [ value, updateState] 
} 
Thread Thread
ipavlenko profile image
Igor Pavlenko Author • Edited

Yes, I can, thanks!
Just wonder why this is not implemented in react.

But you have a little issue in your example.
You use current state, not the last state in you fragment.
Be careful with sequential updates or use callback in setState call to reference prevState

Thread Thread
wozzo profile image
Warren

Missed the useState call. Fixed now. I imagine it's not been implemented because they're going for a more minimalist approach. I.e. By giving us the simplest of hooks we can as above create more complex behaviours if we need.

Collapse
aqrojo profile image
aqrojo • Edited

There's a custom hook that works similar to the the old setState, take a look if it's what you're looking for:
github.com/streamich/react-use/blo...

Collapse
ipavlenko profile image
Igor Pavlenko Author

Yes, it is very useful, thanks!
Just wonder why this is not implemented in react.