7 ms·
Data Fetching for Single-Page Apps
- efilife 2y agoShould have "in react" in the title
- gr4vityWall 2y agoI think it's fascinating how data fetching has been a mostly solved problem in Meteor for years. I understand why you'd use Tanstack Query or similar solutions most of the time. I wish the mental overhead of using them was smaller.
- morbicer 2y agoI would expect a bit more in-depth article from Martin Fowler website. The shown implementation is naive and prone to bugs, for example a race condition. If this id is rapidly changed (say from 1->2), and the first request arrives last, you think you are looking at user 2 but you've loaded data for user 1. const [user, setUser] = useState<User | undefined>(); useEffect(() => { const fetchUser = async () => { const response = await fetch(`/api/users/${id}`); const jsonData = await response.json(); setUser(jsonData); }; fetchUser(); }, [id]); If you don't know what you're doing, use Tanstack Query libs or read a better article. - https://tanstack.com/query/latest https://tanstack.com/query/latest - https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect https://maxrozen.com/race-conditions-fetching-data-react-wit...
- yamumsahoe 2y agoour workaround on this is to use a fetch wrapper that resolves all similar requests to the same inflight requests. awful but works.
- _fat_santa 2y agoThese days unless a react app needs to do something really special, I always reach for and recommend others reach for Tanstack. Currently have a react frontend that's like 50k LOC and it's been chugging with Tanstack Query since day 1 and we have had zero regrets. It's truly one of the best React libraries out there right now.
- hu3 2y agoFor line of business applications, a quick 80/20 solution is putting a spinner blocking the screen when I click the [edit user 1 button].
- dspillett 2y agoIf you are going to block further activity, to be safe block future requests in code too (a check on the event handler that might make the request most likely) in case someone tries to automate the app via browser extension or bookmarklet. Just blocking clicks with a UI overlay doesn't always cut it. Or in case some fool on your dev team calls the events to automate (or for other reasons trigger) something that wasn't intended to be called that way, of course, though once you start defending against iffy practise from within you are fighting a battle you are going to lose!
- kitkat_new 2y agosounds more like 20/20 solution ux-wise better immediately hide user1 and show a loading button and use rxjs's switchmap
- hu3 2y agoHow would rxjs's switchmap prevent the user from clicking user2 button? Also your proposed solution involves a lot more moving pieces. Sounds like a 20/80 solution.
- kitkat_new 2y agoyou mean user1 button? It would throw away the previous http request and users 1 data wouldn't even show up Hiding the elements/div would prevent the user from clicking that button. I don't see how it is 20/80. Switchmap is just a different way of doing things, and hiding the deiv instead of blocking doesn't add really add more effort as well. So I don't see how it's a lot of effort while also missing a lot of the desired features?
- hu3 2y ago
- Rapzid 2y agoAlso useEffect callback is run after the component mounts. I often use memo when kicking off async processes on component mount.
- madeofpalk 2y agoAs in useMemo to make API calls? That is definitely not correct. React explicitly makes no guarantees about how infrequently the fn is called or how long the value is cached for.
- Rapzid 2y agoIt doesn't matter for 99.9% of use cases how long React caches it if your using it to debounce read requests.
- madeofpalk 2y agoSure, if you're using it to memoize a calculation. But triggering an api request having side effects is 100% incorrect.
- Rapzid 2y agoWhy?
- donjoe 2y agoUseMemo should not be used for fetching/kicking off a fetch either. UseMemo fans should be pure. Using logic that belongs into useEffect (logic that happens _outside_ the reactive flow) could potentially lead to other side effects which are very hard to debug. Just a example: a lot of fetch implementations are using fetch with a cache triggered in useMemo returning immediately. You will probably have a setState somewhere in the flow which will terribly interrupt react and break your page. In case you trigger a native fetch, you've got no way to cancel the call due to the missing cleanup fn.
- 2y ago
- knallfrosch 2y agoThe missing syntax highlighting (or the absence of any highlighting) makes it really hard to read. Plus the article only refers to React, but it could have stayed a bit more abstract about the techniques.
- FjordWarden 2y agoI know that Martin Fowler is your God, and that my denigrations upon this divinity will not go unpunished, or that this guy is not Martin Fowler, but what has this guy ever build to convince me that he actually knows what he is talking about? Maybe I am missing that or something else, but here I read that "Today most applications can send hundreds of requests for a single page", like one would hope there to be a sort of role within the software enterprise that would actively try to discourage people from being stupid like that. Hey, at least when DHH jumps on the third rail of the hypermedia bandwagon I can laugh about the 500ms delay of a dropdown to show a calendar in his mail app, and I respect him for that.
- vrnvu 2y agoThose who can't do, teach.
- chimpanzee 2y agoThis saying is a virus.
- chrisandchris 2y agoAnd all of us went through education, taught by people who (in your words) couldn't do, so that we now can go ahead and do.
- toastercat 2y agoYep this is why I refuse to read any text books or documentation. If they were any good, the author wouldn't have written it!
- nin247 2y agoI agree that there are some ill conceived resources out there but there are some who walk the walk and talk the talk: - Erich Gamma contributor to eclipse as well as JUnit (Design Patterns: Elements of Reusable Object-Oriented Software) - Kent Beck key contributor to JUnit - Joshua Bloch key author of the collections API in java (Effective Java) - Donald Knuth - James Gosling creator of Java and the Java programing language book
- tuyiown 2y agoI am horrified. I didn't see mentioned, proper data fetching _must_ happen before UI rendering if you want to have consistent behavior with classic HTML/HTTP apps, e.g. the current page content stays displayed until the received html starts to be rendered (with the actual data for pure HTML). You loading feed back _has_ to happen from the interacted page in first intent. If you want to have an after routing/rendering loading feedback, such as skeleton or so, you still can do it, but it will be opt-in, not an after thought of savage data fetching and rendering that really might happens as the application gains features and diverts from the simple POC patterns. Proper data fetching and rendering cannot happen without a router. Remix solved this with their updated react-router, I know that this router has a bad rep with breaking changes, but they finally landed the implementation that neatly cover most if not all the use cases for routing with dynamic code imports and data fetching.
- janci 2y ago> if you want to have consistent behavior with classic HTML/HTTP apps Why is that desirable? I see it more like a limitation of server-rendered web apps. Many times you can show useful UI before actual data is fully loaded (i.e. search / filter controls or basic data you already have). Certainly, cascading fetching is undesirable and you should know what data you need to fetch and start the requests as soon as possible, but not necessarily before the route transition occurs.
- leovingi 2y ago>Many times you can show useful UI before actual data is fully loaded (i.e. search / filter controls or basic data you already have). It can be done, yeah, but it has to be handled very carefully because it runs the risk of causing more issues than it solves. I can't count the number of times I've used the AWS Console, loaded a page, clicked on a control, only to find that the data that was loaded a few milliseconds before caused the elements on the page to shift so now I clicked on a completely different button, started the process to load a new page and now have to reload the old one and wait for the entire page to finish loading or risk a misclick again.
- beejiu 2y ago
- ramesh31 2y agoThe how is of course extremely simple. But when is the real question. You can do a full send on every route load, but at that point you might as well just do SSR. Dealing with stale data is a nightmare, but you want to have at least some client side inter-page caching to avoid redundant API calls. I've never found a perfect solution here.
- ibash 2y agoThe most common mistake I see is putting data fetching in the view layer. React hooks caused this because by default there’s no sensible place to fetch data. So unless you know ahead of time, any complex single page ends up with complex and hard to track network requests. The solution is really simple: pull data out of the view layer and make it a first class citizen. — An exercise: imagine you’re building a tui instead of a web app, but you’re forced to use the exact same code for app state and data fetching… what would that code look like?
- boredtofears 2y agoReact has always just been the view layer. I'm not sure how hooks made the situation any worse, you're just using a hook (usually useEffect) instead of a class component method or componentDidMount. I don't understand what it means to "pull data out of the view layer and make it a first class citizen". If you're writing a React app, you are building a UI and will need to handle data in your view layer somewhere. You either hand-off that works to a library like Tanstack Query or you manage it yourself.
- wildrhythms 2y agoContrast to Angular which has a 'services' concept where this data fetching logic can live happily divorced from the view layer. https://v17.angular.io/guide/architecture-services https://v17.angular.io/guide/architecture-services
- branko_d 2y agoThe original promise of React was: UI = f(state) The problems come when you modify state in response to rendering the UI. This seems deceptively natural (and in fact seems encouraged by on-line tutorials), but leads to "spaghetti fetching" when composing components together - it creates a "feedback loop" that modifies state just because some component happens to mount, which can then modify state further, then cause further mounting/fetching etc... A better approach is to treat fetching as an explicit state change. If user clicks on a button, you do the fetch and modify the state. If that causes some components to be mounted - so be it, but does not cascade any further.
- beejiu 2y agoThe article sort of touches on this, but in my experience working with React the most important thing is to keep as much as you can declarative. When you start doing things in an imperative way, particularly when they are async, that's when you run into problems. It's one of the reasons I find GraphQL such a good fit.
- samradelie 2y agoBleugh. Who is this article for? (good bait from the poster) Anyone who's done any kind of meaningful SPA dev knows this pattern does not scale & for newbies, this is poison. Instead of talking high-level framework agnostic code design and the multitudes of ways to fetch data (route based, state stores, authentication hooks, subscriptions, model composition , to name a few ); author goes deep into outdated React anti-patterns. Everyone who has commented on this is spot on.