loading...

What is the standard way to keep UI state and backend state synced during updates? (React and Node)

lennythedev profile image Lenmor Ld Updated on ・2 min read

Let's say i have a Node-Express backend with a REST API and a React frontend that has some editable Card. On App load, I fetch an items array and do a setState

componentDidMount() {
    axios.get('/items').then(() => {
        this.setState({ items: res.data })  // res.data is array of items
    })
}

When user updates the card, I send a PUT or POST request to the backend,
which updates the card details (with or without DB doesnt matter, just assume backend state is updated). good.

My question is, what's the best way to update the UI ?
Is there a standard way when doing REST?

Here are the ideas I could come up with:

  • On my server PUT/POST route handler, i could return items array, including the one updated. On UI, I could then do a simple setState({ items: res.data }). Returning the entire items array seems expensive though, considering only one item is updated.

    • At least backend is source of truth, if update fails, i could easily tell UI error happened.
  • On my server Put/POST route handler, i could return only updated item.
    I would then have to find and replace the updated item in my state and do a setState({ items: res.data })

    • Simple enough, but it feels like i'm doing extra work. But since my data structure is an array, I have to replace entire array in UI state.
    • Or is there a better way to update only one item in an array in state, or maybe better to change my data structure to an object, so setState is optimal.
  • On my server Put/POST route handler, i could return a status code/message to signal UI that operation succeeded and now I can update UI state.

  • On UI side, I do the update first, then send the updates to backend.

    For some reason if it fails in backend, then I rollback UI changes (might be tricky?)

  • Use localStorage in between?

any other ideas?

This is probably handled better in GraphQL and using state management like Flux,
but if i'm doing it really vanilla Node and React, what's the best way?

Let me know if my question isn't clear enough, i could elaborate

Thanks!

Posted on by:

lennythedev profile

Lenmor Ld

@lennythedev

webdev @ Autodesk | Someone used to call me "Learn more", and I'm spending forever to live up to it. You'll find me dabbling in random stuff πŸ‘¨β€πŸ’» or missing a wide open shot in πŸ€

Discussion

markdown guide
 

Hi Lenmor,

What I would suggest is changing how your store the items in your UI state. For example, instead of storing an array of items, I would store an object, with the keys being the items id property:

setState(_.keyBy(items, 'id'))

Then, I would use your second idea (POST/PUT returns the updated resource). When you go to update the local state after the server responds to the request, you can easily update only the updated item:

setState({
    ...state.items,
    [response.data.id]: response.data
})
 

Thanks! I was used to having an array before but the idea of using Objects is really growing on me. My app would most likely involve a lot of quick changes in the object's attribute, so this makes a lot of sense.

 

I'm afraid there is no universal answer. All your ideas are potentially good solutions, depending on the particular idiosyncrasies of your app.

On my server PUT/POST route handler, i could return items array, including the one updated.

As you say, the good thing about this is that your backend is the indisputable source of truth and you get the entire current state after an update operation. This might be desirable if you expect multiple users to update the array of items concurrently and it is important that the users don't see stale data. The other advantage is that you need to do less work on the client side. The client can just discard the previous state after an update operation, instead of having to merge the update result with the previous state.

However, the larger your array gets, the less practical this approach becomes. Also, if it is really important to keep the state updated in real time, this approach by itself is not enough.

On my server Put/POST route handler, i could return only updated item.

I'd say this is quite standard strategy.

I don't know a lot about React, but isn't it supposed to take care of only updating the UI nodes that have actually changed when you update the state? This depends a lot on how you are managing your state, but even if you need to set a new array to the state of the component, I don't think there's a huge computational cost involved.

On my server Put/POST route handler, i could return a status code/message to signal UI that operation succeeded and now I can update UI state.

I don't see any advantage in this solution over the previous one. That is, unless the payload you are sending to the server is huge and you need to cut down bandwidth usage, but I'd say that's very unlikely the case.

The advantage of getting the updated item back from the server is that you get any transformation that the server might have performed on the item.

On UI side, I do the update first, then send the updates to backend.

I've seen some applications that do that. I personally think it is bad user experience to act as if something has been updated and then show an error saying that "yeah, it didn't actually go through, sorry about that". I'd rather just have some feedback that the operation is in progress and see the updated state once it has succeeded

This is just my personal opinion, though, if you think this will enhance your user experience, is as valid as any other option. I can see it as a valid approach in an app that behaves synchronously and uses a remote server to back up data, but doesn't depend on it. In that scenario you might even implement a retry system and only cascade the error to the UI when something goes really wrong.

 

Thanks for the very detailed response
At this point, the project is in its early stages, and all of these ideas will definitely help me plan the project better

 

"On UI side, I do the update first, then send the updates to backend". This is the right way.

 

I'm starting to see this very often, and recently learned that it's called "optimistic rendering/UI updates"

Definitely a pattern to explore