I have an offline React web app where all data is stored locally in indexedDB. There is no server other than the file hosting for static assets. I am getting to the point where I am starting to look into using redux now but I am trying to understand the tradeoffs between moving more data into the store and continuing to rely on the DB. What's the idiomatic way of using a local db with redux?
Currently my app is composed of several container components that each fetch data from the db in componentWillMount
. One option for integrating redux is to keep this mostly the same, with the only difference being the state is kept in the store and data is fetched using actions and thunks.
Alternately, I have seen lots of example code that loads all the data into the store at launch. This makes the whole app more deterministic, easier to test and reproduce. Switching between the main components would happen instantly (at the expense of initial app load). But I lose the benefits the DB provides like indexes and nice queries.
It seems like it would be unreasonable load literally the whole db into the store, at least in my case, that would be about 10MB of data, maybe more. So I will always have at least some components which will need to continue fetching their data on mount. But there's a subset of data which is central to the app and can be argued that table should be loaded in its entirety (this would be about 5,000 to 10,000 objects, probably).
What's the idiomatic way to work with local storage and redux? I get the sense that async fetches in componentWillMount
is not idiomatic if it can be avoided. Even in instances where the state is small enough that it can be fully loaded into the store, is it worth giving up the benefits of a nice efficient query interface?
Edit: I should mention: I am using Dexie, which is a really, really wonderful library for working with indexedDB. It's fast, has a nice query interface, handles migrations etc... I'd really like to continue using Dexie unless there's a really strong reason to do otherwise.
For reference, here's a discussion on this topic on Dexie's github. The general take away form that is "it depends". Not quite the answer I was looking for, so I am hoping to get more insight if possible.
Redux persist is a notable library that allows you to save redux storage into your browser's local storage, session storage, or async storage. In this post, we will create api reducer and product reducer using redux and redux toolkit apis and save the redux store in the browser's local storage.
This library helps you to organize your state in a relational way, with queries and joins as you would expect from an SQL based database. There is a storage adaper for redux or you can use it as a standalone library (redux-database has no dependencies!).
Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state. Using local component state is fine.
Answering this myself with what I've discovered so far. If I better answer comes along I'll be happy to mark it accepted.
TL;DR: It really does depend. The idiomatic way to do things is indeed to put as much in the state as long as makes sense. However, it is not un-idiomatic to asynchronously fetch data from elsewhere when it makes sense. Many applications would simply be impractical otherwise.
Dan Abramov's egghead tutorial (even titled "Building React Applications with Idiomatic Redux") goes with the approach of having all state in the store and persisting it a s one giant blob (or the relevant slice) periodically.
This has the advantage that you use the redux store as usual and persistence is essentially transparent. If your data is small enough where this isn't a problem this is great.
As @seanyesmunt noted, there is redux-persist, which basically does a more sophisticated version of this.
Of course, shortly after that he then rewrites the tutorial to fetch data from an API. At this point you can just pretend that API is IndexedDB instead, it's really no different. You lose some benefits of redux by not having completely deterministic state as a whole, but in many cases you have no choice.
I ended up doing essentially the same thing as Dexie's Redux sample code. Basically, using thunks to async write to the DB on certain actions.
EDIT 2020-12-18: I recommend using dexie-react-hooks and the useLiveQuery() hook. It's an amazing experience to work with takes away all complexity around this. See also this blog post about it.
My old answer was: This question is of large interest to me as well as I have been elaborating with react and dexie for the last project I've been in. I am personally examining how graphql could address this scenario, but I am still learning. I hope to provide an example of a graphql/dexie. Of what I understand, graphql would act as the service layer and its "schema" (backend store) would use the dexie queries required to produce the more flat an simplistic graphql data requirements. I will be looking at some ready-to-use grapql sample from Apollo or Facebook to get started and I believe it will be simple to use. I generally don't think it scales to read entire db into memory. And I believe application startup is crucial to end users so I really hope to find a perfect architecture for this. And currently my hope goes to Graphql.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With