Interesting introduction to suspense, didn't know about it. A word of caution might be that it is still an experimental feature [0], so you should probably not be throwing it into production just yet. But when it gets released as stable, it could really improve a lot of sites!
I feel like Suspense has been in development for a decade now. I know, I know.. They should not release it until they are comfortable about its stability. But still, all the teasers and pushed back roadmaps are not helping at this point.
This is because I feel like it's gonna be great for our apps and can't wait to try it on production though.
Perhaps we'll get a release for Christmas or something? I empathise with this point of view though. Luckily, it's in the "experimental" release branch, so you can at least test it out on your side projects and get used to the APIs.
Yeah, it is based on throwing promises that are not resolved. (which is weird but kind of makes sense)
They have been reluctant to discuss the details there, I guess it's because the details might change before the production release so they don't want to spell the actual inner workings out just yet.
It’s not meant to be a quality tutorial. It’s a spammy content-marketing campaign that this company are running. They plan to publish 288 of these in a single month.
They’ve already been banned from posting these to a site similar to HN.
I don't know that I will ever be happy with lazy loaded UIs over a more traditional "Deliver everything first, update later" approach. Hopefully Suspense is a step to solving the problem.
I live in Australia, so there's a perceptible ~300ms delay for every action in react-like loaded later UIs that aren't hosted in Australia, which is most of the tools that I use. They feel clunky and broken, and the amount of times you miss-click because something pops in suddenly and moves the button you wanted down the page. I don't think it's the UI they think they've built.
I don't think it will ever be good enough to throw 20 requests and wait for everything to update, bounce the page around and at long last be intractable. I would rather receive a 2mb page right now, than a 200kb page that slowly grows to a 2mb page over the course of 20 components individually loading themselves.
> a 2mb page right now, than a 200kb page that slowly grows to a 2mb page over the course of 20 components individually loading themselves.
Isn't the point that the 200kb is static code that can be served immediately, while the rest can't? Regardless of whether the remaining 1.8mb is built on the server or client, it still isn't available "right now"
I think what he is saying is since there is a network delay of 300ms for every request, it's better for him to make a single request for a large file than to have to make 10 requests for 200k files and wait 300ms * 10.
You're right, and HTTP/2 was supposed to be a major boon here, but the problem is actually that the UI itself only loads these things once they've been rendered by the framework which is often after another component has loaded them, and even if they can be ran in parallel the response times can still vary, causing the UI jiggle you often see.
This isn't really a problem unique to high latency either, if you have a patchy connection in transit or for some other reason, the UI will suffer.
> but the problem is actually that the UI itself only loads these things once they've been rendered by the framework which is often after another component has loaded them
That just sounds like bad front end coding. A good framework used properly would not have that issue.
Most of the time it is though. I can understand if you have interacted with a component and now it needs to load new data. But on first page load, all the data you intend to show them you should be able to fetch and send with the initial request.
> all the data you intend to show them you should be able to fetch and send with the initial request.
Sure, but if it requires data from five different services and significant compute time, the initial request is going to be very slow. Users are more likely to bail out if they see nothing for a few seconds than if they immediately see a loading screen that lasts for a few seconds.
It's true, there are definitely use cases for lazy-loading UI. I would wager the majority of the time lazy-loaded UI is only present because the engineering team wanted to use new tools and not because there was a requirement to ease long compute calls though, but I'm speculating.
I don't know that I will ever be happy with lazy loaded UIs over a more traditional "Deliver everything first, update later" approach.
There's a nice middle ground.
In the app I work on very little is included at start up. It's literally just the components for the first screen you see. Then it pre-loads more components whenever the browser is idle based on what the user is likely to need. If the user does something that needs a component that isn't available yet it lazy loads it as usual.
If you only use lazy loading the user has to do something that needs a component and then wait until it's available. The strategy I use means there's an additional phase that utilises the time when the browser is idle, so it's much more likely everything is available before it's needed. It works well.
Freudian slip? Sounds about right though. The usability of huge portions of the web has deteriorated markedly in the last few years due to the over use of client-side frameworks.
> the amount of times you miss-click because something pops in suddenly and moves the button you wanted down the page
Browsers should have an option to let you send click events to what was under the mouse 200ms before it was registered. But it would be a colossal PITA to implement.
the misclick because of slow loading/moving components drives me batshit crazy. esp when the click loads a new page: need to go back, wait.. safe to click it now? oops nope!! repeat
It's unclear to me what the alternative is. Would you prefer less interactive, but server-side rendered pages? Latency is latency, and if the closest node to you is somewhere in US West 2, the problem isn't react, the problem is the application is widely distributed enough for you to get acceptable response times.
If you do server-side rendered pages, you still have to make the round-trip to get the next full HTML page. Switching to Vue or Svelte or JSPs isn't changing that.
Not only this, but proper loading states for anything that is happening asynchronously. I am so sick of web apps that show absolutely no sign that a request is in progress.
That is what "Suspense for Data Fetching" is going to help with. It is already perfectly possible to handle data fetching nicely, it just isn't incredibly easy. When Suspense for Data Fetching goes stable, it will be trivial to do right.
That would help movement between pages in a single-page application, though cold boot times will still be less than desirable. If I immediately go to the SPA, and then navigate from page A to page B and the prefetching hasn't completed yet, it can be a jarring experience. I've occasionally clicked on the wrong thing in a UI because the website repainted as I clicked, causing the DOM to shuffle around considerably. New Reddit seems to be a good example of this problem today.
The site doesn't need to be non-interactive, just load the data you intend to show right away in the initial request. Have your 10 interactive components pre-filled, then they can update via web request after that. Single interactions are fine, but when the page initially loads and has to then load 10 other components, the latency adds up really fast and makes it all feel clunky. It still matters after the initial load, just not as much.
An example, when loading a Jira ticket, you have to wait for the page to be sent to you, but it's not usable yet, then you wait for the individual areas of the page all to be sent to you, and as each one loads in at a different time the page goes all over the place and it's not clear when it's actually done and you can safely click stuff without your click target jumping away.
After that, interacting with a single part of the Jira ticket can still induce a load, but it's just the one, and it's expected and I can tell when it's done.
React Suspense, with hooks and fp-ts has given our team a massive leg up in terms of rapidly building out our products new front ends. Being able to combine typed functional programming with the functional-like abstractions given to you by React nowadays makes for a very nice, very straightforward to debug app, without bringing in dozens of dependencies to get this behaviour.
How interesting! I've been wanting to use fp-ts for a while now. How did you manage to convince your team to give it a go. It's certainly very different than other orthodox approaches to React (or TS for that matter)?
Have you had any particular problems / downsides of using it?
And lastly have you considered ReasonML instead? That's the other thing I've been following closely but it never feels quite ready to start working with, for someone not well versed in FP that is.
To your first question: simply put, the easiest way was slipping in usage of Either<L, R> for handling “successful failure” states; error handling in Typescript is still not fine grained enough, even with async functions (maybe even especially), so Either and Maybe/Option have been a big help.
And once you have those, you might as well have them implement the same “interface”, and now you’re cooking with functors ;)
No joke, it was error handling in successful promise resolves that made it an easy sell.
I adore Reason — I use it extensively myself, but as I also adore OCaml this shouldn’t be surprising. The downside is that it’s a harder sell for a mostly backend team; it can definitely be used to great effect today, but Typescript for all its downsides is easier to use right now.
Speaking of downsides: the major one with fp-ts (and io-ts) is some of the inscrutability of it’s more powerful abstractions for programmers who are not well versed in typed functional programming. But that’s okay: just don’t use them! You can get quite far with just the easy to understand concepts, and introduce things like EitherT or Task/IO and similar as the team becomes more confident with composing these data types!
With GraphQL you could in theory grab all the data a page needs in one request. Suspense seems to only be useful if you are making multiple requests.
Not sure what Apollo has to do with anything though.
So I'm not entirely clear on the advantage that Suspense has over the typical pattern of loading data in componentDidMount, and just having a bit of logic that checks whether your data has loaded or not and renders the spinner or the actual contents. It's not really a hard pattern to implement, though sure, it takes a few extra lines. Seems like the <Suspense> component just kind of abstracts this a bit? What am I missing?
I had the same question as you, but I think that the advantages are that (1) the parent is in control of the spinner, but (2) the child is in control of the data.
In most apps I've worked with, either (1) or (2) doesn't hold.
Also on this topic, the beta React lets you treat loading of both child components and or child data dependencies at a chosen level, bringing them in line with Error Boundaries.
I think going all on on components is very easy to reason about. Same direction React Router went with component based routing making it very easy to for example have:
- logged in user portal
- catch all errors and show a fallback UI
- lazy load child components by routes with fallback loader UI
- use a loader fallback potentially for data dependency too.
I mean, it's not perfect and I can see issues people are mentioning, but it feels pretty good to develop with.
Add to this styled components and everything is so component based it's really nice. One main paradigm for the whole front-end.
I don't think it's the best thing ever, but I've enjoyed the newer approaches when working with them.
A lot of the React Suspense talks explore the concept of "rhythm" and Suspense was built to give the developer greater control of the dance and flow of loading states between components. From simply things that you could presumably bubble up into parent component state like "wait until everything loads, not just some of it" to much more complex dances like "don't show a loading screen at all if this part of the data arrives in the next 200ms, otherwise wait for this other part, show these three components in this specific order, then everything else as it comes in", with all sorts of things in the middle including basic buffering of things to particular timings of animation requested steps to lower "jitter" frequency of your UI as the Framework helps loading data clump into batches instead of individual component each individually signaling state changes for rerenders.
It is as pedestrian as you describe. It is an opinionated loading framework that binds timing and component responsibility...just like backbonejs or any other popular solution...except this is tied to the heavy react ecosystem. It doesnt change the way anyone thinks about data.
It's weird how the article mentions that before Suspense there was a waterfall issue. But as far as I understand Suspense introduces the waterfall issue. If you have nested components that need data, the data has to load serially rather than in parallel which creates a waterfall and React devs don't seem to know how to fix this issue.
There is no good way to to solve it other than just to use the appropriate tools like react-saga or placeholder state for components.
If you try to make nested components load at the same time consequences can be unpredictable, suspense lacks fine grained control so it is basically a convenient shortcut, same as react state mixins were at the time.
I appreciated your honest opinion. I'm way too invested to move away, but I've often felt that things are getting overengineered, with the layers of complexity endlessly accumulating - real progress should be making things simpler.
That said, React Suspense looks like it's an improvement of a common pattern, simpler to write and understand. Perhaps it's achieved by pushing the complexity "down" into the library, instead of letting the user manage it every time.
My hope is that one day, all the lessons from React will be incorporated into browsers themselves, to clear the field for saner web development. Seeing how Web Components is going though, I'm not holding my breath..
This looks super cool, and I can immediately see how it'd be immediately useful in production apps both because of potential use-cases and how straightforward it seems to integrate. Is there anything similar in development within Vue land, or is this intrinsically tied to the React render model?
67 comments
[ 3.2 ms ] story [ 122 ms ] thread[0] https://reactjs.org/docs/concurrent-mode-suspense.html
This is because I feel like it's gonna be great for our apps and can't wait to try it on production though.
Also several other topics following the same template: https://bekk.christmas
I love the different color patterns.
I'm inferring suspense is based on exceptions to interrupt unrenderable components, but it would be nice if the author told me.
They have been reluctant to discuss the details there, I guess it's because the details might change before the production release so they don't want to spell the actual inner workings out just yet.
They’ve already been banned from posting these to a site similar to HN.
I live in Australia, so there's a perceptible ~300ms delay for every action in react-like loaded later UIs that aren't hosted in Australia, which is most of the tools that I use. They feel clunky and broken, and the amount of times you miss-click because something pops in suddenly and moves the button you wanted down the page. I don't think it's the UI they think they've built.
I don't think it will ever be good enough to throw 20 requests and wait for everything to update, bounce the page around and at long last be intractable. I would rather receive a 2mb page right now, than a 200kb page that slowly grows to a 2mb page over the course of 20 components individually loading themselves.
Isn't the point that the 200kb is static code that can be served immediately, while the rest can't? Regardless of whether the remaining 1.8mb is built on the server or client, it still isn't available "right now"
This isn't really a problem unique to high latency either, if you have a patchy connection in transit or for some other reason, the UI will suffer.
That just sounds like bad front end coding. A good framework used properly would not have that issue.
Sure, but if it requires data from five different services and significant compute time, the initial request is going to be very slow. Users are more likely to bail out if they see nothing for a few seconds than if they immediately see a loading screen that lasts for a few seconds.
There's a nice middle ground.
In the app I work on very little is included at start up. It's literally just the components for the first screen you see. Then it pre-loads more components whenever the browser is idle based on what the user is likely to need. If the user does something that needs a component that isn't available yet it lazy loads it as usual.
If you only use lazy loading the user has to do something that needs a component and then wait until it's available. The strategy I use means there's an additional phase that utilises the time when the browser is idle, so it's much more likely everything is available before it's needed. It works well.
Freudian slip? Sounds about right though. The usability of huge portions of the web has deteriorated markedly in the last few years due to the over use of client-side frameworks.
Browsers should have an option to let you send click events to what was under the mouse 200ms before it was registered. But it would be a colossal PITA to implement.
import Component from 'component'
instead of lazy loading it ?
If you do server-side rendered pages, you still have to make the round-trip to get the next full HTML page. Switching to Vue or Svelte or JSPs isn't changing that.
An example, when loading a Jira ticket, you have to wait for the page to be sent to you, but it's not usable yet, then you wait for the individual areas of the page all to be sent to you, and as each one loads in at a different time the page goes all over the place and it's not clear when it's actually done and you can safely click stuff without your click target jumping away.
After that, interacting with a single part of the Jira ticket can still induce a load, but it's just the one, and it's expected and I can tell when it's done.
Ant Design has also been a game changer for us.
Have you had any particular problems / downsides of using it?
And lastly have you considered ReasonML instead? That's the other thing I've been following closely but it never feels quite ready to start working with, for someone not well versed in FP that is.
And once you have those, you might as well have them implement the same “interface”, and now you’re cooking with functors ;)
No joke, it was error handling in successful promise resolves that made it an easy sell.
I adore Reason — I use it extensively myself, but as I also adore OCaml this shouldn’t be surprising. The downside is that it’s a harder sell for a mostly backend team; it can definitely be used to great effect today, but Typescript for all its downsides is easier to use right now.
Speaking of downsides: the major one with fp-ts (and io-ts) is some of the inscrutability of it’s more powerful abstractions for programmers who are not well versed in typed functional programming. But that’s okay: just don’t use them! You can get quite far with just the easy to understand concepts, and introduce things like EitherT or Task/IO and similar as the team becomes more confident with composing these data types!
Every other technology ever.
You'd still query and display your data in the same way. Suspense will just be a wrapper around the component displaying the data.
In most apps I've worked with, either (1) or (2) doesn't hold.
(1) The child is in control of the spinner:
(2) The parent is in control of the data With Suspense, the child fetches its own data, but the parent is in control of the spinner: So the Child doesn't need to know the details of how the parent app wants to deal delays.Suspense then seems to make it easier to parallelize the data requests, and have a spinner at the lowest parent with a child waiting for data.
I think going all on on components is very easy to reason about. Same direction React Router went with component based routing making it very easy to for example have:
- logged in user portal - catch all errors and show a fallback UI - lazy load child components by routes with fallback loader UI - use a loader fallback potentially for data dependency too.
I mean, it's not perfect and I can see issues people are mentioning, but it feels pretty good to develop with.
Add to this styled components and everything is so component based it's really nice. One main paradigm for the whole front-end.
I don't think it's the best thing ever, but I've enjoyed the newer approaches when working with them.
If you try to make nested components load at the same time consequences can be unpredictable, suspense lacks fine grained control so it is basically a convenient shortcut, same as react state mixins were at the time.
That said, React Suspense looks like it's an improvement of a common pattern, simpler to write and understand. Perhaps it's achieved by pushing the complexity "down" into the library, instead of letting the user manage it every time.
My hope is that one day, all the lessons from React will be incorporated into browsers themselves, to clear the field for saner web development. Seeing how Web Components is going though, I'm not holding my breath..