top | item 22928608

Restoring React reducer state across browser sessions

46 points| execute_program | 6 years ago |executeprogram.com | reply

11 comments

order
[+] dmix|6 years ago|reply
> Our actual solution is to store the state in our server-side database. This feels wrong at first glance: we're storing a client-side React component's state as an opaque JSON blob in our server-side database, and we're doing that knowing that some of those JSON blobs will go out of date and be unusable in the future. But io-ts and the type system keep us honest here! And this is a convenience feature, so we can always change it later, even if that means throwing away all of the saved states. (When a user finishes a lesson, that record is stored in a separate part of the database.)

That seems very... bold. That said, I could see this being useful for more ephemeral situations where it's okay to not be entirely in sync with the server. Like the user signup example: multi-step forms, or some create-only or override-always sort of arrangement, or maybe some filters for some sorting/slicing data tables, etc.

It's then useful for not being jittery on load + not storing half-baked data just to have semi-persistence of incomplete forms. Quickly rendering existing state is always a win, without resetting it then loading the updated position.

Otherwise I could see this introducing a lot of race conditions and additional work being done post-load to clean up the data.

Since there's a relatively short line here where it just makes sense to rebuild the state, it's probably preferable to utilize this for smaller isolated parts of the site, like a single form's data, instead of the wider state. But still an interesting approach none-the-less, made easier with the reducer pattern...

[+] gary_bernhardt|6 years ago|reply
We only use it for resuming partially-finished lessons, so we're using it in basically the way that you describe. Overall course progress is tracked in a totally different way.
[+] sdegutis|6 years ago|reply
> That seems very... bold.

It's just traditional server-side sessions. Just done more complicatedly to work around React's architecture.

[+] Tade0|6 years ago|reply
Two things I find weird in this approach:

1. Why marry the state stored in the database with any particular implementation of the front-end?

2. If the problem is in the ever changing state schema, why not create migrations for it?

[+] StevenWaterman|6 years ago|reply
Exactly, the ideal solution is the one they dismiss first.

> Solution 1: Store the current step index

Every issue they mention can be solved by assigning each step a UUID and doing proper database migrations when deleting a step so people get reassigned to a neighboring step.

[+] uhoh-itsmaciek|6 years ago|reply
>1. Why marry the state stored in the database with any particular implementation of the front-end?

They seem to have only one front-end implementation to worry about for now, and the client state is most likely pretty generic (they don't really make this clear, but I can't think of anything react-specific you'd want to store in a reducer state).

[+] mikewhy|6 years ago|reply
We did the same at a previous company. This was Redux, so maybe a little different, but it went very smoothly.

We stored a subset of the redux store locally, and a further subset of that was sent to the server. This data is quite prone to changing, so a JSON field in the database is fine. You're not going to do any advanced querying / migrations on it.

Restoring was pretty easy:

- Try to grab from local storage

- Try to read from remote

- Merge those (let local overwrite remote)

- Pass the merged object through a migration function

- Pass the migrated data to `createStore`

The biggest pain point was dealing with TypeScript and migrations. The app only knows if the most recent store interface, so migration functions looked a lot like "old" javascript (`if (foo && foo.bar)`, `typeof foo === 'string'`, that sort of stuff).

Easy persistence / restoring is one of the many things I like about Redux.