[HN Gopher] The Plan for React 18
       ___________________________________________________________________
        
       The Plan for React 18
        
       Author : joeyespo
       Score  : 129 points
       Date   : 2021-06-08 17:43 UTC (5 hours ago)
        
 (HTM) web link (reactjs.org)
 (TXT) w3m dump (reactjs.org)
        
       | kbuchanan wrote:
       | 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.
        
         | Stevvo wrote:
         | 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.
        
           | acdlite wrote:
           | Who are these jerk users? I'm going to give them a noogie!
           | 
           | In all seriousness, I'm sorry you had such a bad experience.
           | That's not what we want the React community to be. Next time,
           | feel free to tag me or someone else on the core team and
           | we'll tell them to cut it out.
        
       | flowerlad wrote:
       | 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.
        
         | danabramov wrote:
         | _> 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_
         | 
         | 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.
        
           | flowerlad wrote:
           | To clarify, I am not talking about the React 18 feature. I
           | have this problem in React 17. On Pagedown key, I throttle
           | the setState calls because calling it too fast causes React
           | to batch the updates. I'll try to make an standalone repro
           | and open an issue in the React repo.
        
             | danabramov wrote:
             | Automatic batching is new in 18 so I suspect something else
             | is up. A repro case would be highly appreciated! Thanks.
        
         | acdlite wrote:
         | 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!
        
           | Sammi wrote:
           | That does sound like React is doing a lot of work to work
           | around some issue. As OP said: "This is an example of React
           | doing too much."
        
             | acdlite wrote:
             | I agree the React implementation is very complex, but in a
             | way that's by design: we add features to React when it
             | allows us to move complexity out of our product code and
             | into a framework.
             | 
             | Like, yes, implementing batching in React was complicated,
             | but in exchange the developer doesn't have to think about
             | it anymore. It just works!
        
       | _the_inflator wrote:
       | Interesting approach: Working Group as a model to allow community
       | participation.
        
       | mdoms wrote:
       | 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.
        
         | lukifer wrote:
         | > Facebook!
         | 
         | 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 wrote:
         | What's funny about hooks?
        
           | recursive wrote:
           | I know this is controversial, but I find them hard to
           | understand. When I call `useState()`, what's the identity of
           | the state that I'm using? What ties the state together
           | between subsequent invocations of my component? For example,
           | I know that strange things happen if you conditionally invoke
           | `useState()`. People like to talk about "functional
           | components", but hooks seem to live and breathe on mysterious
           | side effects that I don't understand.
        
             | jahewson wrote:
             | If only there was some way to discover how things worked...
             | Some website where you could type "how react hooks work"
             | and get dozens of articles and blog posts explaining it.
        
               | mdoms wrote:
               | I understand how they work. That doesn't make the API any
               | less insane.
        
               | recursive wrote:
               | You're probably aware of this, but those things already
               | exist.
               | 
               | Personally, I prefer to use things that make more sense,
               | even if I read dozens of articles and blogs explaining
               | them.
        
               | canadianfella wrote:
               | > If only there was
               | 
               | That's an annoying way to communicate.
        
           | lucas_codes wrote:
           | OP doesn't like them, so they're funny
        
           | mdoms wrote:
           | They are apparently this panacea of elegant stateless code,
           | but the developer is expected to know that multiple calls to
           | useState must be made in the same order every time. Typically
           | we associate APIs that are fragile to out-of-order calls with
           | tightly coupled stateful systems.
           | 
           | Not to mention the hideous use APIs. Thanks you, React, for
           | this array which apparently contains a state and a setter?
        
             | davnicwil wrote:
             | I think your first point gets to a tradeoff that isn't much
             | discussed about hooks- they can be elegant and simple, but
             | only assuming quite a bit of upfront knowledge about how
             | they work.
             | 
             | It's almost like taking the verbosity of class lifecycle
             | methods, and 'pre compiling' it into a form which is
             | terser, yes, but that now only a sufficiently informed
             | reader can grok - the lifecycle is still there, it just has
             | to be modelled by the reader instead of by the code.
             | 
             | Sometimes this is a good tradeoff, but not always.
        
       | tmitchel2 wrote:
       | 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.
        
       | steve_adams_86 wrote:
       | 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.
        
         | danabramov wrote:
         | _> I'm excited about concurrent mode._
         | 
         | 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-....
        
           | steve_adams_86 wrote:
           | That's exactly it! Thank you!
           | 
           | > Tiny nitpick
           | 
           | Haha, 10-4 - I'll drop the habit
        
       | no_wizard wrote:
       | I hope the modules get re-organized to be tree-shakable. Native
       | es module exports would also be nice! Smaller bundle sizes are
       | always a plus
        
         | acdlite wrote:
         | 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.
        
         | acemarke wrote:
         | Agreed that having React available as native ES Modules would
         | be good. There's an open issue on that:
         | 
         | 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.
        
       | tekstar wrote:
       | I use React (well, Preact) every day.
       | 
       | 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?
        
         | jfengel wrote:
         | 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.
        
         | flowerlad wrote:
         | 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.
        
           | e12e wrote:
           | Wasn't react first designed in standard ml, without classes?
           | Then classes were bolted on in the js rewrite - and hooks are
           | closer to the original design?
           | 
           | https://www.reactiflux.com/transcripts/jordan-walke
           | 
           | > So I continued to explore framework-izing these ideas, and
           | I had implemented several iterations of what eventually
           | became React, in a few languages - one of the first
           | explorations began as a rough implementation of the
           | reconciler and component model in Standard ML (CreateClass
           | was a "module function"). This was really great because SML
           | embraces immutability by default which is natural when
           | building React style components. We naturally wanted to
           | deploy UI to web browsers, and at the time, the compile-to-JS
           | landscape was not as mature as it is now - I don't even think
           | source maps existed yet. So it made sense to port that
           | exploration to JavaScript (...)
           | 
           | > One thing I noticed that when people were creating point to
           | point bindings in their more traditional "MVC" app structure,
           | it would almost always end up requiring "computable" bindings
           | which invoke a function anytime a mutable cell had received a
           | "change event". All these "computable bindings" ended up
           | chaining together and small changes would end up causing
           | large recomputation of the majority of the UI. I realized
           | that functions already do transform inputs into outputs, and
           | if we could just find a way to reinvoke those functions
           | repeatedly, and quickly enough, that we could be much more
           | expressive and concise, at not much more performance cost
           | that the chain reaction that "computed bindings" would result
           | in anyways.
        
         | joshxyz wrote:
         | 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.
        
         | no_wizard wrote:
         | 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
        
         | dstaley wrote:
         | 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.
        
         | srpoder wrote:
         | React hooks might be the best feature ever, once you understand
         | it, it provides you a way to write highly reusable code.
        
         | enlyth wrote:
         | 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
        
           | flowerlad wrote:
           | > _pure functional components focused only on how to render,
           | and try to abstract reusable logic into hooks_
           | 
           | Just FYI, once you add hooks, it is neither pure nor
           | functional.
           | 
           | https://mckoder.medium.com/why-react-is-not-
           | functional-b1ed1...
        
             | WorldMaker wrote:
             | They may not be pure, but they are still _functional_. The
             | hooks follow similar laws to Monads. They aren 't entirely
             | monadic and it would have been nice if they were and used a
             | more monadic combinator for bind [1], but they are a
             | relatively pragmatic solution for a language without a
             | strong type system to encode things like algebraic effects
             | and monadic bindings in.
             | 
             | [1] Mostly useless aside: using a .then()able based
             | plumbing would have opened up the possibility of using the
             | async/await combinator language. The names async/await
             | would give the wrong impression especially prior to the
             | actual concurrency changes to eventually ship in React 18,
             | but would have potentially been a more monadic fit.
        
               | flowerlad wrote:
               | > _The hooks follow similar laws to Monads._
               | 
               | And monads are impure [1]. If all your functions are
               | impure then you're not doing functional programming.
               | 
               | [1] https://alvinalexander.com/scala/io-monad-doesnt-
               | make-functi...
        
               | 1_player wrote:
               | > monads are impure
               | 
               | Not necessarily. The IO Monad (Haskell et al.) is impure,
               | a monad is just a functional abstraction that doesn't
               | have anything to do with purity at all.
        
               | WorldMaker wrote:
               | Yes, I stated that. Those functions are impure. Purity is
               | a lovely goal, but purity also isn't a defining
               | characteristic of functional programming, it's a modern
               | pursuit. I've met enough classic LISP practitioners that
               | lived their whole programming lives in the most impure of
               | functional programming, that I would never want to tell
               | them to their face that what they did didn't count as
               | functional programming because of all the leaky impurity
               | in LISP (due to pragmatic considerations of the time).
        
               | flowerlad wrote:
               | > _purity also isn 't a defining characteristic of
               | functional programming_
               | 
               | Disagree. It is in fact the defining characteristic of
               | functional programming.
        
               | e12e wrote:
               | It may be defining of _pure_ functional programming. But
               | not for  "functional programming". Some arguments for why
               | (and indeed some discussion for why not, too !) :
               | https://wiki.c2.com/?FunctionalProgramming
        
           | enumjorge wrote:
           | > You basically stick to writing pure functional components
           | focused only on how to render
           | 
           | If you're using hooks like useState or useEffect I wouldn't
           | consider those functional components pure.
           | 
           | Hooks provide some nice syntactic sugar, which is not
           | nothing, and make it easier to share logic between
           | components. In my experience hooks have made my code easier
           | to read, but they haven't simplified it. The side effects and
           | state might not be inlined but they're still there. If
           | anything they've made it less explicit because some of the
           | details are hidden behind the magic that the React runtime
           | uses to add state to functions.
        
             | nexuist wrote:
             | They're technically not pure, but they're as close as we
             | can get to functional-style state handling: declare
             | dependencies upfront so the caller knows exactly what
             | they'll get when they execute your function. Fully state-
             | less code achieves basically nothing; you need to "escape
             | the hatch" eventually to work with the rest of the
             | architecture. Hooks are very beautiful escape hatches that
             | let you deal with persistence without having to sacrifice
             | the rest of your function's body to it.
        
               | bern4444 wrote:
               | Really well said.
               | 
               | And if you really wanted to make it 'pure', you could
               | easily write a hook with an explicit return type that
               | wraps the type of the initial value. If you're using
               | typescript, you can then limit the possible types of the
               | generic to only monads.                   type State<T> =
               | val as T;              const useStatex =
               | <T>(initialState: T) => {             const [state,
               | setState] = useState(initialState);             return
               | [state, updateState] as [State<T>, (val: T) => void];
               | }
               | 
               | This new hook, useStatex, has an explicit type definition
               | that indicates something stateful is taking place. Same
               | as Futures. You can take this even further in the typing
               | limiting the generic to only allow certain types for the
               | underlying values to be monads, or even more simply
               | type State<T> = Promise<T> | Array<T> | Option<T>
               | 
               | So you avoid an extra layer of nesting like
               | State<Future<Array<T>>>
        
             | bern4444 wrote:
             | I'm sure the parent author knows this
             | 
             | But the beauty of hooks is as you say reusable statefull
             | behavior. It also lets you treat your functional components
             | more like a pure function in my opinion.
             | 
             | If the hooks you use are poorly designed, then yeah, it may
             | be more difficult. But well designed and implemented hooks
             | make your component appear more like a pure function.
             | 
             | The state is (more) decoupled from the UI code than before
             | and lets me easily reuse behaviors across components.
        
         | thatswrong0 wrote:
         | So you're saying you have no idea why they're making changes
         | because you haven't been following along, despite using the
         | library every day...?
         | 
         | The communication about the "why" of new features has been
         | extremely clear. E.g. for hooks:
         | https://reactjs.org/docs/hooks-intro.html
        
           | tekstar wrote:
           | Your first sentence is correct. I'm quite happy using it the
           | way I use it and don't hit any really sharp edges.
           | 
           | Thanks for the link, I remember when Hooks came out but I
           | didn't feel the need to adopt them, I'll take a look again.
        
       | travisd wrote:
       | Does this include suspense for data fetching?
       | 
       | Edit: seems so! Post links to a release announcement on GitHub
       | which says it's "fully" supported.
        
         | danabramov wrote:
         | I'd say we can say Suspense for data fetching is "done" when
         | Server Components (https://reactjs.org/blog/2020/12/21/data-
         | fetching-with-react...) and built-in Suspense Cache
         | (https://github.com/reactwg/react-18/discussions/25) are
         | finalized. I would expect this to happen at some point during
         | the 18.x release timeline, but maybe not in the initial
         | release.
         | 
         | 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.
        
       | jaredcwhite wrote:
       | 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.
        
       | cglong wrote:
       | I've been out of React for a little while now; what's the tl;dr
       | for concurrent rendering and why was there concern about it
       | breaking existing apps?
        
         | CGamesPlay wrote:
         | 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.
        
         | danabramov wrote:
         | Not exactly a tl;dr but some examples of features unlocked by
         | it:
         | 
         | - 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.
        
         | wccrawford wrote:
         | 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.
        
       | gervwyk wrote:
       | 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.
       | 
       | Thanks again! And keep up the good work.
        
         | e12e wrote:
         | 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"
         | 
         | https://www.reactiflux.com/transcripts/jordan-walke
        
       ___________________________________________________________________
       (page generated 2021-06-08 23:03 UTC)