I just wanna give a shoutout to Facebook for finding a balance between rapid, innovative development on a major library without constantly introducing breaking changes. On the backend I'm a Clojure dev, and this approach has long been a standard in clojure.core which has earned my loyalty for many years. Wish more projects could be like this.
Whilst the major changes are not technically breaking, they are culturally breaking; e.g. ask for help how to do something with classes, and you are likely to get someone telling you to "just use hooks instead". I've never encountered another library whose users are such opinionated assholes.
I'm excited about concurrent mode. We're using it in production to help make a search function 'feel' faster, and it's very effective. Of course our focus is still making things actually faster, but concurrent mode goes a long way way in improving user experience which is essential.
One thing I need to wrap my head around is avoiding unnecessary work with useDeferredValue, for example. I've got something set up which will defer multiple values, but I know the user will only want the most recent value by the time something can render. As a result, once values arrive it'll kind of cycle through each rendered value rapidly before stopping at the last one. I guess I need to implement some sort of throttling and/or debouncing under the hood better - this probably isn't up to concurrent mode to solve for me.
I'm glad to see batching being focused on. I have code which implements batching to some degree, and it's always struck me as so awkward that I can't rely on React to make good decisions for me in this area. The abstraction required in a context provider or component to accomplish this is fairly ugly and really gets in the way of focusing on the component's core responsibility. I think this will be a great improvement.
I use it 2014-style. Class-based components, componentWillMount, render, callbacks, and that's about it.
I love this workflow, and generally structure all my UIs this way regardless of platform - have a state struct and then fully render the UI as a function of the state. To me, that's the big hurrah for using React.
But I have no clue why React is at version 18 and why it keeps getting new features. I'm perfectly happy making quite complicated UIs with the pattern I know well. Should I be following along? Does it matter?
I personally fell in love with hooks after initially disliking them, you should give it a try, maybe in a toy personal project, to see if you like it. It is great for separation of concerns.
You basically stick to writing pure functional components focused only on how to render, and try to abstract reusable logic into hooks, and expose only what you need
For example, you could make a useApi() hook and inside your component just do const { data, loading, error } = useApi('/endpoint'), so you can hide everything you don't need away from the rendering logic
I find the function-based components much more elegant than class-based components. The semantics of Javascript classes are confusing, and the new notation is very concise. (Especially with an IDE, such that "refactor this pile of tags into a function" is a one-click process.)
The useState hooks are a tiny bit clearer than the setState semantics. The effect hooks are less clear, but all told, the new mechanisms for handle global state and side effects better without Redux. (Redux is neat, but after working with it for years, I just have to conclude that in most cases it's just too much mental overhead compared to a more idiomatically Javascript solution.)
There's nothing wrong with continuing to use class-based components, but I think you'll find that everybody else is going to gradually deprecate it. The key facts about the work flow -- state to render function to surprisingly efficient DOM reconciliation -- remains the same.
As someone who was initially resistant to hooks, I actually find that they're a more expressive API to how I was already thinking about my applications. There's footguns for sure, just like there are with class components, but I found that rewriting my class components with hooks instead actually made the code cleaner and easier to reason about. That being said, it's possible the benefit simply came from the rewrite, but even with newer components, I feel like hooks are a better API.
I am with you. React as originally designed made sense to me. You render the screen point-in-time and React takes care of updating the screen efficiently. This is all I need from React. Everything else is bloat.
In this way react is choose your own adventure. There is no current signal that the way class components work will change and I don’t exactly expect that to happen any time soon if at all. Rather then new features are aimed at developers with more complex use cases and make heavy use of asynchronous data fetching in a way that lends itself to concurrency.
If this isn’t you I’m sure at least the general performance improvements will be nice otherwise I don’t see why you can’t just keep doing what you’re doing
I think it's less about being pure or functional, but more about being "ergonomic". I abhored class-based components from day 1, but on hooks everything just clicked.
>".. I use it 2014-style ..."
are you using any type system eg TypeScript or Flow ?
I am asking because I do not remember them being used back then, so wondering if you had upgraded there.
Also what do you use for 'whole app' state handling (rather than component level) ?
Asking because React Context feature seems to be the right fit for the 'whole app' state handling, but it was not there back in 2014.
I also like you picked up preact for smaller project.. just because the size is so small. But for lager things (eg over 20K lines of JS) I seem to be staying with React.
Really looking forward to new server side components and suspense.
Also, kudos the the React / facebook team for building such an exceptional framework. React has really enabled small teams like ours to build large applications and even a framework! It takes a lot of dedication and careful planning to create such a versatile lib for a broad audience. 8 years down the road and the team is still keeping it together while innovating web-dev to new frontiers.
Interesting, I never did notice this bit in my previous readings of this interview:
> I had also put the foundation in place, to ensure that React components could be server rendered - and that feature was more so inspired by demand and constraints at the time than any specific technology.
"Jordan Walke
Transcript from Thursday January 26th, 2017
Facebook Engineer | Creator of React.js & Reason"
We do intend to ship a ES module build of React in the near future. Because that's a breaking change that could require significant changes to existing apps (i.e. to update the imports), we'll likely wait until the next major release cycle.
However, note that tree-shaking probably won't help much in the case of React. React isn't a library of independently useful features; it's a cohesive framework where features work together. We also have a really small API surface area. So there's no much to "shake" apart.
Arguably the main `react` package would benefit slightly from tree shaking, but those exports are already really small. The `react` package doesn't contain that much implementation; it mostly just calls into internal React DOM to schedule updates.
However, there really isn't anything to tree-shake in React. The renderer implementation is effectively a single consolidated set of logic that handles all work for all types of components. So, there's no unused functions to get shaken out.
Automatic batching appears to cause problems, because the screen doesn't update when it needs to.
Here's the scenario: User is holding down the down arrow key. On each key event you have to update the screen so that appears to scroll up. But React gets in the way by batching setStates, and this causes the screen updates to be jumpy. Now you have to find a workaround. This is an example of React doing too much.
>Note: React only batches updates when it’s generally safe to do. For example, React ensures that for each user-initiated event like a click or a keypress, the DOM is fully updated before the next event. This ensures, for example, that a form that disables on submit can’t be submitted twice.
If you see a problem like the one you're describing, please file an issue in the main React repo, and we'll have a look. I'm not sure how you could have experienced this behavior since we released the alpha an hour ago.
We have a mechanism to handle this exact scenario. We classify certain user input events, like keypresses and clicks, as "discrete" events. Updates that are triggered from discrete event will always be processed sequentially. We don't batch multiple events. Although we do batch multiple setStates within the same event, which is different. "Automatic batching" refers to the updates themselves, not the events.
We call non-discrete events (like mousemove) "continuous", and for those we will batch updates across multiple events.
We've been testing this at Facebook for a while and we think our model is really solid, handling all the common cases and a bunch of edge cases, too. If you try it out and find something unexpected, please let us know and we'll fix it!
Does anyone know if the alpha builds will work with react native? I'm really hoping so because the flickering between transitions when using latest relay is super annoying to get around.
I'd love to see web components support greatly enhanced in React 18. It's literally the only major JS library used on the frontend which still offers poor WC support.
I think the gist of it is that JavaScript doesn't have threads, or isolated state. So your code can theoretically do anything it wants, but the React concurrency stuff is riding on your code only using a specific set of APIs, and does things like calling your functions on cloned instances with different props. If you aren't writing your code "in the React way" it very quickly leads to very confusing inconsistent behaviors.
At a guess, I'd say "Side effects in render functions". People might be doing things in render that aren't generally considered safe or wise, and forcing concurrent rendering on them would run that code multiple times immediately, instead of the expected "once per render".
The new version apparently doesn't do that, unless you specifically use one of the new features, which means that you have accepted the other caveats for that scenario.
Maybe somebody else has the energy to summarize them. :-)
The concern was because the old approach was to change the behavior globally. The new approach is to make it opt-in when you use specific new features that rely on it.
Two things about React will never stop being funny to me,
1. An entire generation of front end developers have staked their careers on a framework developed by Facebook. Facebook!
2. The hooks API. I honestly thought this was a joke when I first saw it. Developers will talk about the elegance of functional components then go and use the hooks API.
IMO there are far greater concerns with centralized API services, which are nearly always opaque, closed-source, and incentivized towards vendor lock-in (AWS being the elephant in the room).
"Staking careers" is also a little much; React isn't that hard to learn (it's near-trivial compared to .NET or iOS development), and any developer worth their salt will have to frequently retrain into new patterns and frameworks during their career.
There can be legitimate concerns with power concentrations of open-source software based on the incentives of its stewards (Chrome comes to mind); but ultimately React carries a relatively small footprint, and can always be forked [0] if it goes in a direction that developers don't like.
[+] [-] kbuchanan|4 years ago|reply
[+] [-] Stevvo|4 years ago|reply
[+] [-] steve_adams_86|4 years ago|reply
One thing I need to wrap my head around is avoiding unnecessary work with useDeferredValue, for example. I've got something set up which will defer multiple values, but I know the user will only want the most recent value by the time something can render. As a result, once values arrive it'll kind of cycle through each rendered value rapidly before stopping at the last one. I guess I need to implement some sort of throttling and/or debouncing under the hood better - this probably isn't up to concurrent mode to solve for me.
I'm glad to see batching being focused on. I have code which implements batching to some degree, and it's always struck me as so awkward that I can't rely on React to make good decisions for me in this area. The abstraction required in a context provider or component to accomplish this is fairly ugly and really gets in the way of focusing on the component's core responsibility. I think this will be a great improvement.
[+] [-] danabramov|4 years ago|reply
Tiny nitpick--we'd like to stop referring to it as a "mode" since the new gradual strategy is opt-in per feature. :-)
>As a result, once values arrive it'll kind of cycle through each rendered value rapidly before stopping at the last one.
Have you tried the latest alpha? The behavior you're describing sounds like a bug we fixed a few months ago. See https://github.com/facebook/react/issues/17185#issuecomment-....
[+] [-] tekstar|4 years ago|reply
I use it 2014-style. Class-based components, componentWillMount, render, callbacks, and that's about it.
I love this workflow, and generally structure all my UIs this way regardless of platform - have a state struct and then fully render the UI as a function of the state. To me, that's the big hurrah for using React.
But I have no clue why React is at version 18 and why it keeps getting new features. I'm perfectly happy making quite complicated UIs with the pattern I know well. Should I be following along? Does it matter?
[+] [-] enlyth|4 years ago|reply
You basically stick to writing pure functional components focused only on how to render, and try to abstract reusable logic into hooks, and expose only what you need
For example, you could make a useApi() hook and inside your component just do const { data, loading, error } = useApi('/endpoint'), so you can hide everything you don't need away from the rendering logic
[+] [-] jfengel|4 years ago|reply
The useState hooks are a tiny bit clearer than the setState semantics. The effect hooks are less clear, but all told, the new mechanisms for handle global state and side effects better without Redux. (Redux is neat, but after working with it for years, I just have to conclude that in most cases it's just too much mental overhead compared to a more idiomatically Javascript solution.)
There's nothing wrong with continuing to use class-based components, but I think you'll find that everybody else is going to gradually deprecate it. The key facts about the work flow -- state to render function to surprisingly efficient DOM reconciliation -- remains the same.
[+] [-] dstaley|4 years ago|reply
[+] [-] srpoder|4 years ago|reply
[+] [-] flowerlad|4 years ago|reply
[+] [-] no_wizard|4 years ago|reply
If this isn’t you I’m sure at least the general performance improvements will be nice otherwise I don’t see why you can’t just keep doing what you’re doing
[+] [-] thatswrong0|4 years ago|reply
The communication about the "why" of new features has been extremely clear. E.g. for hooks: https://reactjs.org/docs/hooks-intro.html
[+] [-] joshxyz|4 years ago|reply
[+] [-] audit|4 years ago|reply
I am asking because I do not remember them being used back then, so wondering if you had upgraded there.
Also what do you use for 'whole app' state handling (rather than component level) ?
Asking because React Context feature seems to be the right fit for the 'whole app' state handling, but it was not there back in 2014.
I also like you picked up preact for smaller project.. just because the size is so small. But for lager things (eg over 20K lines of JS) I seem to be staying with React.
[+] [-] gervwyk|4 years ago|reply
Also, kudos the the React / facebook team for building such an exceptional framework. React has really enabled small teams like ours to build large applications and even a framework! It takes a lot of dedication and careful planning to create such a versatile lib for a broad audience. 8 years down the road and the team is still keeping it together while innovating web-dev to new frontiers.
Thanks again! And keep up the good work.
[+] [-] e12e|4 years ago|reply
> I had also put the foundation in place, to ensure that React components could be server rendered - and that feature was more so inspired by demand and constraints at the time than any specific technology.
"Jordan Walke Transcript from Thursday January 26th, 2017 Facebook Engineer | Creator of React.js & Reason"
https://www.reactiflux.com/transcripts/jordan-walke
[+] [-] no_wizard|4 years ago|reply
[+] [-] acdlite|4 years ago|reply
However, note that tree-shaking probably won't help much in the case of React. React isn't a library of independently useful features; it's a cohesive framework where features work together. We also have a really small API surface area. So there's no much to "shake" apart.
Arguably the main `react` package would benefit slightly from tree shaking, but those exports are already really small. The `react` package doesn't contain that much implementation; it mostly just calls into internal React DOM to schedule updates.
[+] [-] acemarke|4 years ago|reply
https://github.com/facebook/react/issues/11503
However, there really isn't anything to tree-shake in React. The renderer implementation is effectively a single consolidated set of logic that handles all work for all types of components. So, there's no unused functions to get shaken out.
[+] [-] flowerlad|4 years ago|reply
Here's the scenario: User is holding down the down arrow key. On each key event you have to update the screen so that appears to scroll up. But React gets in the way by batching setStates, and this causes the screen updates to be jumpy. Now you have to find a workaround. This is an example of React doing too much.
[+] [-] danabramov|4 years ago|reply
This does not sound correct. Quoting directly from the page on automated batching (https://github.com/reactwg/react-18/discussions/21):
>Note: React only batches updates when it’s generally safe to do. For example, React ensures that for each user-initiated event like a click or a keypress, the DOM is fully updated before the next event. This ensures, for example, that a form that disables on submit can’t be submitted twice.
If you see a problem like the one you're describing, please file an issue in the main React repo, and we'll have a look. I'm not sure how you could have experienced this behavior since we released the alpha an hour ago.
[+] [-] acdlite|4 years ago|reply
We call non-discrete events (like mousemove) "continuous", and for those we will batch updates across multiple events.
We've been testing this at Facebook for a while and we think our model is really solid, handling all the common cases and a bunch of edge cases, too. If you try it out and find something unexpected, please let us know and we'll fix it!
[+] [-] travisd|4 years ago|reply
Edit: seems so! Post links to a release announcement on GitHub which says it’s “fully” supported.
[+] [-] danabramov|4 years ago|reply
However, React 18 does include a ton of work around Suspense, including:
- Fixes to quirks in its existing behavior (https://github.com/reactwg/react-18/discussions/7)
- startTransition API which lets you implement the "show old content while new data is loading" UX (https://github.com/reactwg/react-18/discussions/41)
- A whole new server renderer that uses <Suspense> for streaming HTML and hydrating the page in independent parts (https://github.com/reactwg/react-18/discussions/37)
So it's ongoing but maybe the "whole story" including recommended patterns will not quite be in the initial scope in 18.0 release.
I edited the announcement to clarify this.
[+] [-] _the_inflator|4 years ago|reply
[+] [-] tmitchel2|4 years ago|reply
[+] [-] jaredcwhite|4 years ago|reply
[+] [-] cglong|4 years ago|reply
[+] [-] CGamesPlay|4 years ago|reply
[+] [-] wccrawford|4 years ago|reply
The new version apparently doesn't do that, unless you specifically use one of the new features, which means that you have accepted the other caveats for that scenario.
[+] [-] danabramov|4 years ago|reply
- https://github.com/reactwg/react-18/discussions/41
- https://github.com/reactwg/react-18/discussions/37
Maybe somebody else has the energy to summarize them. :-)
The concern was because the old approach was to change the behavior globally. The new approach is to make it opt-in when you use specific new features that rely on it.
[+] [-] mdoms|4 years ago|reply
1. An entire generation of front end developers have staked their careers on a framework developed by Facebook. Facebook!
2. The hooks API. I honestly thought this was a joke when I first saw it. Developers will talk about the elegance of functional components then go and use the hooks API.
[+] [-] lukifer|4 years ago|reply
https://en.wikipedia.org/wiki/Genetic_fallacy :P
IMO there are far greater concerns with centralized API services, which are nearly always opaque, closed-source, and incentivized towards vendor lock-in (AWS being the elephant in the room).
"Staking careers" is also a little much; React isn't that hard to learn (it's near-trivial compared to .NET or iOS development), and any developer worth their salt will have to frequently retrain into new patterns and frameworks during their career.
There can be legitimate concerns with power concentrations of open-source software based on the incentives of its stewards (Chrome comes to mind); but ultimately React carries a relatively small footprint, and can always be forked [0] if it goes in a direction that developers don't like.
[0] https://preactjs.com/
[+] [-] beckingz|4 years ago|reply