GithubHelp home page GithubHelp logo

Comments (19)

shuding avatar shuding commented on May 5, 2024 25

Thanks @aequasi !

We tested Local Storage and IndexedDb when started implementing this on the ZEIT dashboard. And we learned many things from it:

  • Local Storage is IO heavy (it stores data on the disk), and cache read/write happens very frequently when the website starts to load. It will slow down the rendering and other resources.
  • IndexedDb is async, which means the SWR cannot return the data from cache synchronously. So when navigating (back and forward) through the website with cache, React will always render without data first.
  • and some other UX feedback about client side storage (e.g.: loading skeleton vs out of dated data from local cache when opening the website)

But it might be a good idea to support cache fallback (e.g.: Memory -> IndexedDb), expiration and other features. Anyway, supporting multiple caching mechanisms is definitely an important option. πŸ‘

from swr.

rauchg avatar rauchg commented on May 5, 2024 8

We also extensively experimented with SSR for our dashboard, and the calculus is that it's just not worth it.

With Suspense + fast hydration + JS budgets + fast APIs, we'll never render a skeleton in most cases anyways. We'll suspend until we have data, then render it all at once in the ideal case.

The benefit? You get rid of all the server complexity, you only have a single error tracking and observability surface (the client side), and your TTFB is always consistently fast globally thanks to ZEIT CDN :chefkiss:

from swr.

derindutz avatar derindutz commented on May 5, 2024 6

In case it's helpful, here's useSWR with localforage as a persistent cache fallback that I use: https://gist.github.com/derindutz/179990f266e25306601dd53b8fbd8c6a. You can switch out localforage for whichever caching mechanism you want. I'm using it in production so if there are any suggestions you have for improvement I'm all ears 😊

from swr.

rauchg avatar rauchg commented on May 5, 2024 6

As an anecdote, we did an extensive experiment with IndexedDB and it was awful from a product perspective. Disks are slow and customers tend to want strong reads from the kind of apps and dashboards that you use SWR for.

There might be some use-cases for consumer apps where you're ok to restore to old data (like an Instagram feed) and then clearly designate as offline, where IndexedDB might make sense.

But even then I'd carefully consider the "network-first" strategy with a timer and things like that, kinda like workbox is approaching SW.

from swr.

netspencer avatar netspencer commented on May 5, 2024 4

I’d love to see a layered cache architecture. for speed and such, i think the memory cache should always be the top level. and then the actual network requests are the lowest level

the ability to then add intermediate cache levels would be very powerful (for my usecases at least)

in other words, the first cache that should be checked shall remain the in memory map, which is sync, will ensure the above list works as expected. but then adding something like indexdb or websql as a layer before making a network request would be great

from swr.

morrys avatar morrys commented on May 5, 2024 4

Hello to all,
I wanted to offer you the possibility to use
wora/cache-persist (documentation). This library allows you to use all storage in synchronous mode through the use of a memory cache. All communication processes towards storage are queued and performed asynchronously. (natively can handle inmemorycache, localStorage, sessionStorage, indexedDB, AsyncStorage, customStorage )

I created this library to manage the persistence of Relay & Apollo and I also used it to manage offline mutations.

Let me know if you are interested in its integration.

from swr.

sergiodxa avatar sergiodxa commented on May 5, 2024 4

The cache Layer is already separate, you can import it with import { cache } from 'swr'

What I do to keep the SWR cache in sync with an off-line available storage (in web with localStorage, in RN you can use AsyncStorage I think), is to subscribe to cache changes and update the storage when something changes there and before rendering the app I read from that cache and fill the SWR cache with the data.

I built this library https://github.com/sergiodxa/swr-sync-storage to sync with WebStorage APIs, you can probably use something similar to sync with RN AsyncStorage or IndexedDB or another option.

This is a great way to work actually because some of those storage options are async by nature but you want to be able to read from cache in a sync way instead, this is why SWR cache is completely sync to get data, this allow SWR to read immediately from cache when data is already cache and revalidate in an async way, if SWR had to read from an async cache it should have to always send data as undefined even if that data was already cached.

What you want to add here is a second cache layer, used for more persistent cache (in your case offline), so your AsyncStorage could be this second layer, where you will update data from the first layer and you will use it to fill the first layer before starting your app.

from swr.

morrys avatar morrys commented on May 5, 2024 3

Hi @quietshu,
I wrote to learn about the vision of the project. I agree with the need to make a library lighter and highly configurable (the goal of every well-made library :)) ... A curiosity, for you redux is light or not?

I agree with points 1 and 2, while with regard to point 3, I would suggest that you think about a concept of refresh & fetch policy, as found in Relay & Apollo.
Specifically, there are 4 types:

  • store-or-network: Reuse data cached in the store; if the whole query is cached, skip the network request
  • store-and-network: Reuse data cached in the store; always send a network request.
  • network-only: Don't reuse data cached in the store; always send a network request.
  • store-only: Reuse data cached in the store; never send a network request.

As for the integration of my library it is sufficient (points 1 & 2 are managed by the library):

  • provide for the possibility of configuring a custom cache
  • point 3

I think the topic of caching in the web & in react-native is a common problem in all open source projects and that's why I created this library. So any feedback from you will be very important to me.

Thanks

from swr.

shuding avatar shuding commented on May 5, 2024 1

@aequasi

Regarding IndexedDb, does it have to return synchronously?

It's okay to have async cache, and we can also read from memory cache because it's always a stream πŸ‘that's why a layered cache architecture (as @netspencer mentioned too πŸ™) can be very helpful.

from swr.

morrys avatar morrys commented on May 5, 2024 1

Hi guys,
to be able to do a PR (even in draft) I need some information from you.

Premise:

In order to manage all the storage it is necessary to provide a concept of asynchronous restore / hydration (indexeddb, asyncstorage etc ..). In this issue I described how this is managed in react-relay-offline

In short, it would be necessary to provide two phases:

  • the first one in which the application is offline (in react-native the detection of the network is asynchronous) & with the empty cache (or with the data received from the SSR server)

    • the restore function is performed (both to detect the network and to retrieve data from storage)
    • fetch is not performed
    • the first renderer is executed in a loading state or with the data retrieved from the server
  • the second phase is activated by the restore callback

    • the state reconciliation is performed between the state present in the store and the data recovered from the server (if present)
    • the network state is detected
    • the hook is refreshed

Both wora/cache-persist and the library mentioned in this issue #69 natively manage this behavior.

It would be useful to have your indication / collaboration on how to create and configure the cache externally and how to better manage the two phases in useSWR.

from swr.

shuding avatar shuding commented on May 5, 2024 1

Closing this issue as I believe most of our goals are covered by the 1.0 release: https://swr.vercel.app/blog/swr-v1.

from swr.

cryptiklemur avatar cryptiklemur commented on May 5, 2024

Fair points @quietshu !

Regarding IndexedDb, does it have to return synchronously? Presumably, if you are wanting to use IndexedDb, you would have to accept the fact that its asynchronous, and you would have to have the 'non-data' view.

from swr.

cryptiklemur avatar cryptiklemur commented on May 5, 2024

ideally we’d be able to specify a faster cache (like lru or redis) for SSR though, so the user never sees a flash of no data

from swr.

shuding avatar shuding commented on May 5, 2024

Hi @morrys,

Thank you for your input! I think what you have proposed consists of these features:

  1. support of async cache
  2. cache provider API which supports events too
  3. API to pause/resume fetching

Instead of making all the cache options (IndexedDB, ...) and network detectors built-in, using them
as APIs will be much more flexible. So people can build their own cache or use a plugin if they really need to customize the cache machinesm behind, and for 90% users who don't need that, SWR will still be lightweight and highly customizable.

I think the third feature of above will be the easist to implement (just a boolean in the options / config provider). But the first 2 things require a lot of changes still.

from swr.

shuding avatar shuding commented on May 5, 2024

Thanks @morrys!

First of all Redux is very lightweight. It's just a 3kB lib (like SWR) but most importantly it's just a simple and powerful concept (Reducer). But there're a lot of plugins and libs around that basic concept.

Same for this lib. "SWR" is the concept of stale-while-revalidate, in which:

  • stale is the cached data
  • revalidate is the way to get the fresh data

That's why I think we need make each part customizable:

  • data: cache API (or SSR, local state)
  • request: fetcher function, network options, subscription, etc.

instead of extending the SWR concept with more features. And I believe the scenarios you provided can be implemented with those 2 APIs too.

And for sure we can make it easier for plugins to extend this lib.

from swr.

morrys avatar morrys commented on May 5, 2024

Exactly @quietshu :) the important thing is to consider the possibility of extending the concept. I think some things should have been handled natively in redux (but that's another story).

At this point I would say that the main theme is to make the cache customizable. Is it a work in progress?

from swr.

mojtabast avatar mojtabast commented on May 5, 2024

I'm working on a react native app that needs to be synced with server all the time but frequency of data changes for some of them are low so we can show the cached version while revalidating (even if the user is offline).

SWR are storing data in memory and data will be lost in some situation like closing app. it's not offline-capable as well.

I read the whole thread and there are some valid points. Unfortunately I had to switch to my SWR alternative solution which is initializing from storage (and put in memory), write/read from memory and sync with storage after revalidating (write), and then same API as SWR.

I think SWR can fix this by separating the cache layer. because the only thing I had to change was changing the cache location. by providing some APIs, we can have the built-in memory cache and at the same time let others to implement their own cache layer like IndexedDB, ... as a separate package.

from swr.

mojtabast avatar mojtabast commented on May 5, 2024

Interesting @sergiodxa, Thanks for sharing. I checked your code out, I only have one concern which is it seems it's not possible to keep them in sync efficiently right now because swr's notify doesn't passing the affected item, it just notify the listeners something has changed. what I saw in your code as well is you're reading the whole caches and putting them in storage again after each change.

As other guys mentioned IO is a heavy task and I'm not sure how the performance will be for applications with a large cache/data.

What I noticed here is there is no way to :

  • recognize only the affected cache
  • distinguish set/delete/clear in subscribe to perform the right action for it.

from swr.

sergiodxa avatar sergiodxa commented on May 5, 2024

There is a PR I opened it to allow subscribed to know the updated key #365, that will improve the way to do this kind of second cache layer support.

from swr.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.