[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)