How do I invalidate a resource created by react-cache?
I can fetch data from API:
const FooResource = createResource(id => fetch(`/foo/${id}`)); // return a promise, or async/await
// inside render...
const fooResponse = FooResource.read(id); // suspends if not in cache; renders if in cache
return <div> {fooResponse} </div>;
However, when I update the data on the backend I am unable to refetch the data on the frontend.
This is the only somehow official documentation that I was able to find: https://github.com/sw-yx/fresh-concurrent-react/blob/master/apis/react-cache.md
Is there some undocumented API that I can use? 🤔
In general — you can't, and this is why it's "unstable". Don't use it for anything except demos and tinkering. We'll likely replace the whole thing with a different API.
As of now react-cache uses LRU (least recently used) caching policy. By this policy, the least recently used entries are invalidated first.
The size of the cache can be set using function unstable_setGlobalCacheLimit.
I couldn't find a function for explicit cache invalidation in the project. I also think that it is good news, 'cause dealing with cache is generally a hassle. It seems like LRU is going to make it easier for most React users.
Manual cache control might find its way in the future versions of react-cache as more developers embrace the technology and discover new use cases that need a custom approach, but I doubt it's something one should consider for now.
There is a lot more control over the cache is required using react-cache. It seems it is written considering only client-side rendering(though it works on both csr and ssr).
On the server, there are high chances that only a few specific API's need to be cached for a given interval. All user-specific API's or data should not be cached in react-cache.
react-cache should give control to differentiate caching behavior on both client and server as both environments have completely different use cases.
Currently, the react-cache source code doesn't point to any invalidation capability. It makes sense to need invalidation, to update the results for example after you've added a new comment or post, as well as use suspense with post/put/delete requests, which should not be cached by default in the first place.
Related
I am struggling with some details about finding a solution to make an Angular / C# app available offline.
My idea would be to use upup.js the get the business logic for the SPA in Angular available offline. upup.js uses service workers to do so. I would store the data required for the offline app using angular-localForage which uses IndexedDB and falls back to WebSQL and localStorage in case.
The problem is, that I have to make files and images available offline too without requiring the user to visit the page they are being used on and I am worried about the maximum quotas. I could store them using either upup.js and adding those files as assets, or store them with angular-localForage as blobs. IndexedDB is supposed to be unlimited by now if I am informed correctly? I couldn't find any maximum quota for a service worker though, as the upup.js solution would use. The AppCache is deprecated, so I wouldn't use that... Or maybe I understood something completely wrong, or there is even another, better solution? Anyhow, the question is:
TL;DR: What is the better way to store files for an AngularJS offline application: angular-localForage (IndexedDB etc.) or a Service Worker (upup.js) and what are the maximum quotas for each solution? Or is there an even better solution?
In my opinion Service Worker (SW) is better than tradition local storage. Plus SW can also use indexedDB.
For the implementation, it is very depending. How your app structure, what technologies of front-end being with with your angular app, what is your main goals of using SW...?
1. Traditional JS loading, you are likely merge all the JS file in one... like app.js contains everything.
And you also don't care about Push Notification neither any other cool features that SW offering.
=> For this case it seem like upup.js suite you the best.
NOTE : beware that upup.js attempt to registering SW on it own, so it likely blocking or complexified your work on expanding feature of SW.
2. Advanced AMD user, where almost all of your JS chopped to small pieces... like fooCtrl.js, barCtrl.js, etc...
For sure you don't want to configure like 100+ files of JS, and further more you will got a lot of html template to load.
=> In this case I will suggest you to use sw-toolbox . A very powerful and light weight tool made by Google. At initial if you are not familiar with SW concept yet, you will have a bit of trouble setting it up for your site (but it won't be longer than a day of you are an advanced JS developer)
After all has configured, all become so very simple. For example this is how I cache all of static content in my site.
self.toolbox.router.get(/(.js|.css|.png|.jpg|.json|.html)/, self.toolbox.fastest);
3. You don't care about what kind of technology at front-end side. You just interest with SW.
=> Simply go for sw-toolbox it's a real time-saver for basic configuration. And if you want to expand the usage of SW, you can just expand it by your own will.
I'm building an application that presents sensitive patient information.
One of my routes shows presents an HTML fragment received from the server that contains an image of a patient document.
I need to ensure that that document is not accessible on disk after the page is closed
That would be a really big issue if it was left there.
I noticed that the route was caching and I had to remove it from $templateCache to detect changes. Is that just cached in memory or is it local hdd?
A broader question might be: does Angular cache anything on persistent storage beyond what the browser already does according to HTTP cache control headers?
This really depends on the abstraction level you look at:
A Javascript app cannot write arbitrary files to the disk - there is the well-known browser sandbox, and this also applies to angular.js apps. So, if you are not specifically using the Browser offline APIs such as LocalStorage, Cookies, ... in your own code, there will be "just" the usual browser cache. So you should be fine.
Caveat 1: Sometimes it seems to be quite hard to control the browser caches, there are multiple ways browsers cache things as you already mentioned. They can usually be by http headers. So if you configure your HTTP headers very carefully you should be fine.
Caveat 2: There are multiple ways operating systems cache things and they may or may not save some of these caches to disk (as a simple example consider the windows hibernation file: there is probably a copy of your image in there when you had it open in your browser upon hibernation.). This cannot be controlled by a browser app - but for most applications it does not really matter.
I'm getting to be a fan of David Nolen's Om library.
I want to build a not-too-big web app in our team, but I cannot really convince my teammates to switch to ClojureScript.
Is there a way I can use the principles used in om but building the app in JavaScript?
I'm thinking something like:
immutable-js or mori for immutable data structures
js-csp for CSP
just a normal javascript object for the app-state atom
immutable-js for cursors
something for keeping track of the app-state and sending notification base on cursors
I'm struggling with number 5 above.
Has anybody ventured into this territory or has any suggestions? Maybe someone has tried building a react.js app using immutable-js?
Edit July 2015: currently the most promising framework based on immutability is Redux! take a look! It does not use cursors like Om (neither Om Next does not use cursors).
Cursors are not really scalable, despite using CQRS principles described below, it still creates too much boilerplate in components, that is hard to maintain, and add friction when you want to move components around in an existing app.
Also, it's not clear for many devs on when to use and not use cursors, and I see devs using cursors in place they should not be used, making the components less reusable that components taking simple props.
Redux uses connect(), and clearly explains when to use it (container components), and when not to (stateless/reusable components). It solves the boilerplate problem of passing down cursors down the tree, and performs greatly without too much compromises.
I've written about drawbacks of not using connect() here
Despite not using cursors anymore, most parts of my answer remains valid IMHO
I have done it myself in our startup internal framework atom-react
Some alternatives in JS are Morearty, React-cursors, Omniscient or Baobab
At that time there was no immutable-js yet and I didn't do the migration, still using plain JS objects (frozen).
I don't think using a persistent data structures lib is really required unless you have very large lists that you modify/copy often. You could use these projects when you notice performance problems as an optimization but it does not seem to be required to implement the Om's concepts to leverage shouldComponentUpdate. One thing that can be interesting is the part of immutable-js about batching mutations. But anyway I still think it's optimization and is not a core prerequisite to have very decent performances with React using Om's concepts.
You can find our opensource code here:
It has the concept of a Clojurescript Atom which is a swappable reference to an immutable object (frozen with DeepFreeze). It also has the concept of transaction, in case you want multiple parts of the state to be updated atomically. And you can listen to the Atom changes (end of transaction) to trigger the React rendering.
It has the concept of cursor, like in Om (like a functional lens). It permits for components to be able to render the state, but also modify it easily. This is handy for forms as you can link to cursors directly for 2-way data binding:
<input type="text" valueLink={this.linkCursor(myCursor)}/>
It has the concept of pure render, optimized out of the box, like in Om
Differences with Om:
No local state (this.setState(o) forbidden)
In Atom-React components, you can't have a local component state. All the state is stored outside of React. Unless you have integration needs of existing Js libraries (you can still use regular React classes), you store all the state in the Atom (even for async/loading values) and the whole app rerenders itself from the main React component. React is then just a templating engine, very efficient, that transform a JSON state into DOM. I find this very handy because I can log the current Atom state on every render, and then debugging the rendering code is so easy. Thanks to out of the box shouldComponentUpdate it is fast enough, that I can even rerender the full app whenever a user press a new keyboard key on a text input, or hover a button with a mouse. Even on a mobile phone!
Opinionated way to manage state (inspired by CQRS/EventSourcing and Flux)
Atom-React have a very opinionated way to manage the state inspired by Flux and CQRS. Once you have all your state outside of React, and you have an efficient way to transform that JSON state to DOM, you will find out that the remaining difficulty is to manage your JSON state.
Some of these difficulties encountered are:
How to handle asynchronous values
How to handle visual effects requiring DOM changes (mouse hover or focus for exemple)
How to organise your state so that it scales on a large team
Where to fire the ajax requests.
So I end up with the notion of Store, inspired by the Facebook Flux architecture.
The point is that I really dislike the fact that a Flux store can actually depend on another, requiring to orchestrate actions through a complex dispatcher. And you end up having to understand the state of multiple stores to be able to render them.
In Atom-React, the Store is just a "reserved namespace" inside the state hold by the Atom.
So I prefer all stores to be updated from an event stream of what happened in the application. Each store is independant, and does not access the data of other stores (exactly like in a CQRS architecture, where components receive exactly the same events, are hosted in different machines, and manage their own state like they want to). This makes it easier to maintain as when you are developping a new component you just have to understand only the state of one store. This somehow leads to data duplication because now multiple stores may have to keep the same data in some cases (for exemple, on a SPA, it is probable you want the current user id in many places of your app). But if 2 stores put the same object in their state (coming from an event) this actually does not consume any additional data as this is still 1 object, referenced twice in the 2 different stores.
To understand the reasons behind this choice, you can read blog posts of CQRS leader Udi Dahan,The Fallacy Of ReUse and others about Autonomous Components.
So, a store is just a piece of code that receive events and updates its namespaced state in the Atom.
This moves the complexity of state management to another layer. Now the hardest is to define with precision which are your application events.
Note that this project is still very unstable and undocumented/not well tested. But we already use it here with great success. If you want to discuss about it or contribute, you can reach me on IRC: Sebastien-L in #reactjs.
This is what it feels to develop a SPA with this framework. Everytime it is rendered, with debug mode, you have:
The time it took to transform the JSON to Virtual DOM and apply it to the real DOM.
The state logged to help you debug your app
Wasted time thanks to React.addons.Perf
A path diff compared to previous state to easily know what has changed
Check this screenshot:
Some advantages that this kind of framework can bring that I have not explored so much yet:
You really have undo/redo built in (this worked out of the box in my real production app, not just a TodoMVC). However IMHO most of actions in many apps are actually producing side effects on a server, so it does not always make sens to reverse the UI to a previous state, as the previous state would be stale
You can record state snapshots, and load them in another browser. CircleCI has shown this in action on this video
You can record "videos" of user sessions in JSON format, send them to your backend server for debug or replay the video. You can live stream a user session to another browser for user assistance (or spying to check live UX behavior of your users). Sending states can be quite expensive but probably formats like Avro can help. Or if your app event stream is serializable you can simply stream those events. I already implemented that easily in the framework and it works in my production app (just for fun, it does not transmit anything to the backend yet)
Time traveling debugging ca be made possible like in ELM
I've made a video of the "record user session in JSON" feature for those interested.
You can have Om like app state without yet another React wrapper and with pure Flux - check it here https://github.com/steida/este That's my very complete React starter kit.
Here are the numbers
min+gzip 26k
gzip 90k
original 450+k
And React doesn't have many features in it's documentation. Why is it so big?
I have a feeling that it's the implementation of lightweight DOM. But I want to be sure.
React does quite a bit! The biggest nonobvious part of React is probably the events system -- not only does React implement its own event dispatching and bubbling, it normalizes common events across browsers so that you don't need to worry as much about it. For example, SelectEventPlugin is a built-in event "plugin" which provides an onSelect event which behaves the same way in all browsers.
The virtual DOM implementation does take a decent amount of code as well; a lot of effort is spent on performance optimization, which is why the unminified version includes ReactPerf, which is a tool for measuring rendering performance. In updating the DOM, React also does some convenient things for you like maintaining any input selection and keeping the current scroll position the same.
React also has a few other tricks up its sleeve. One of the coolest is that it fully supports rendering a component to an HTML string even if you don't have a browser environment, so you can send down a page that works even before JS is loaded.
What are you comparing React against? react-15.0.2.min.js is 43k (gzipped), but jQuery is 33k while ember-2.6.0.prod.js is 363k (also gzipped). Obviously these frameworks don't do exactly the same things but they do have a lot of overlap, so I think the comparison is reasonable.
If you're worried about download size, I wouldn't worry too much about JS code contributing to that. Here's an ad which I see on the right side of my Stack Overflow page right now:
Its download size is 95k -- I wouldn't think twice about including an image like that in a page because (even if I was worried about performance) there are usually so many other performance-related things to fix that are more lucrative.
In short, I don't think React is that big, and what size it does have comes from the many small things it does to help you out. You cite React's small API as a reason that React's code should be small, but a better question might be, "How is React's API able to be so simple given all the things it does for you?"
…but that's a totally separate question. :) Hope I answered your question -- happy to expand if I didn't.
A couple of thoughts.. I had some of the same concerns with it's size, but after using it, no joke, I would use it if it was 5MB in size. It's just that good. That said, I did decide to reduce as many dependencies on other libraries as possible. I was using jquery for two things.. ajax and the automatic ajax response and request handling (beforeSend, etc) that would handle when a token was in a response after login, and then make sure every ajax request added it to the Authorization header before sending. I replaced this with a super small simple bit of native javascript. Works great. Also, I was trying to use _underscore. I've replaced it with lodash, which is smaller and faster, although presently I am not using it so may remove it altogether.
Here is one article, of many on google, that I found that has some alternatives using native JS over jquery.
http://www.sitepoint.com/jquery-vs-raw-javascript-1-dom-forms/
planning to launch a comic site which serves comic strips (images).
I have little prior experience to serving/caching images.
so these are my 2 methods i'm considering:
1. Using LinkProperty
class Comic(db.Model)
image_link = db.LinkProperty()
timestamp = db.DateTimeProperty(auto_now=True)
Advantages:
The images are get-ed from the disk space itself ( and disk space is cheap i take it?)
I can easily set up app.yaml with an expiration date to cache the content in user's browser
I can set up memcache to retrieve the entities faster (for high traffic)
2. Using BlobProperty
I used this tutorial , it worked pretty neat. http://code.google.com/appengine/articles/images.html
Side question: Can I say that using BlobProperty sort of "protects" my images from outside linkage? That means people can't just link directly to the comic strips
I have a few worries for method 2.
I can obviously memcache these entities for faster reads.
But then:
Is memcaching images a good thing? My images are large (100-200kb per image). I think memcache allows only up to 4 GB of cached data? Or is it 1 Mb per memcached entity, with unlimited entities...
What if appengine's memcache fails? -> Solution: I'd have to go back to the datastore.
How do I cache these images in the user's browser? If I was doing method no. 1, I could just easily add to my app.yaml the expiration date for the content, and pictures get cached user side.
would like to hear your thoughts.
Should I use method 1 or 2? method 1 sounds dead simple and straightforward, should I be wary of it?
[EDITED]
How do solve this dilemma?
Dilemma: The last thing I want to do is to prevent people from getting the direct link to the image and putting it up on bit.ly because the user will automatically get directed to only the image on my server
( and not the advertising/content around it if the user had accessed it from the main page itself )
You're going to be using a lot of bandwidth to transfer all these images from the server to the clients (browsers). Remember appengine has a maximum number of files you can upload, I think it is 1000 but it may have increased recently. And if you want to control access to the files I do not think you can use option #1.
Option #2 is good, but your bandwidth and storage costs are going to be high if you have a lot of content. To solve this problem people usually turn to Content Delivery Networks (CDNs). Amazon S3 and edgecast.com are two such CDNs that support token based access urls. Meaning, you can generate a token in your appengine app that that is good for either the IP address, time, geography and some other criteria and then give your cdn url with this token to the requestor. The CDN serves your images and does the access checks based on the token. This will help you control access, but remember if there is a will, there is a way and you can't 100% secure anything - but you probably get reasonably close.
So instead of storing the content in appengine, you would store it on the cdn, and use appengine to create urls with tokens pointing to the content on the cdn.
Here are some links about the signed urls. I've used both of these :
http://jets3t.s3.amazonaws.com/toolkit/code-samples.html#signed-urls
http://www.edgecast.com/edgecast_difference.htm - look at 'Content Security'
In terms of solving your dilemma, I think that there are a couple of alternatives:
you could cause the images to be
rendered in a Flash object that would
download the images from your server
in some kind of encrypted format that
it would know how to decode. This would
involve quite a bit of up-front work.
you could have a valid-one-time link
for the image. Each time that you
generated the surrounding web page,
the link to the image would be
generated randomly, and the
image-serving code would invalidate
that link after allowing it one time. If you
have a high-traffic web-site, this would be a very
resource-intensive scheme.
Really, though, you want to consider just how much work it is worth to force people to see ads, especially when a goodly number of them will be coming to your site via Firefox, and there's almost nothing that you can do to circumvent AdBlock.
In terms of choosing between your two methods, there are a couple of things to think about. With option one, where are are storing the images as static files, you will only be able to add new images by doing an appcfg.py update. Since AppEngine application do not allow you to write to the filesystem, you will need to add new images to your development code and do a code deployment. This might be difficult from a site management perspective. Also, serving the images form memcache would likely not offer you an improvement performance over having them served as static files.
Your second option, putting the images in the datastore does protect your images from linking only to the extent that you have some power to control through logic if they are served or not. The problem that you will encounter is that making that decision is difficult. Remember that HTTP is stateless, so finding a way to distinguish a request from a link that is external to your application and one that is internal to your application is going to require trickery.
My personal feeling is that jumping through hoops to make sure that people can't see your comics with seeing ads is solving the prolbem the wrong way. If the content that you are publishing is worth protecting, people will flock to your website to enjoy it anyway. Through high volumes of traffic, you will more than make up for anyone who directly links to your image, thus circumventing a few ad serves. Don't try to outsmart your consumers. Deliver outstanding content, and you will make plenty of money.
Your method #1 isn't practical: You'd need to upload a new version of your app for each new comic strip.
Your method #2 should work fine. It doesn't automatically "protect" your images from being hotlinked - they're still served up on a URL like any other image - but you can write whatever code you want in the image serving handler to try and prevent abuse.
A third option, and a variant of #2, is to use the new Blob API. Instead of storing the image itself in the datastore, you can store the blob key, and your image handler just instructs the blobstore infrastructure what image to serve.