Great video. This is completely asinine though by the react team. Imagine how many devs aren't going to be aware of these nuances. What are they thinking?
@PhilipAlexanderHassialis
Ай бұрын
I am suspecting that this is a "compromise" solution, trying to brute force promises handling inside components that are *theoretically* supposed to be entirely synchronous. Consider that the "use" function doesn't abide by the "rules of hooks". Hence I postulate that they named it that way to make it "easy" for the rest of the community who has been spoonfed to know that if something starts with the word "use" it's a hook.
@jherr
Ай бұрын
They are probably thinking that they want to be cautious to maintain 100% compatibility with previous behavior while still offering new functionality. The key takeway in this video is that you should hoist your promises when using Suspense/use. In that case, as demonstrated, this isn't an issue.
@SeanCTTR
Ай бұрын
I mean, that could be kind of a problem with anything in any language. Including so many things that I’ve already been in react for years. It’s why so many people complain about hooks and useEffect. Even though you can just use them properly and they work fine.
@jherr
Ай бұрын
@@SeanCTTR Yeah, if you don't fight the framework, stuff usually goes pretty smoothly. In this case, hoist your promises outside of the suspense and you'll do fine.
@0xAndy
Ай бұрын
This is the first time I've felt like leaving the React ecosystem in almost a decade.
@odra873
Ай бұрын
I just use any of the api libraries and don’t worry about any fetch problems 😅
@karolbielen2090
Ай бұрын
+1, I like SWR
@rodrigorb2630
Ай бұрын
Man, I feel for folks trying to launch and maintain courses on React in 2024
@blizzy78
Ай бұрын
I love these in the weeds videos, keep em coming
@mertdr
Ай бұрын
Great content Jack! I think passing fetch results to another component in order to fix “use”hook’s behavior ends up with unpractical decoupling. And these examples don’t even cover refetching and loading state (currently loading through suspense), which probably would require passing other props as well. I guess React Query will continue to shine for fetching data in React 19 as well.
@jherr
Ай бұрын
FWIW RQ has an external cache that’s doing a bunch of heavy lifting to give you the impression that your data access is local to the component.
@mertdr
Ай бұрын
IMO it’s another win for RQ since it stores cached data in context and allows to pull cached or fresh data by query key on further requests. I suppose “use” wouldn’t have sort of opportunity because data will be refetched on component recreation (route change or mount/unmount). Maybe there will be a helper function for caching like nextjs’ next/cache (currently experimental) Honestly it’s been almost a year or so since “use” introduced as an experimental hook and this video is probably the first one deep dives its use cases. Thanks a lot for your effort.
@jherr
Ай бұрын
@@mertdr To really use `use` you need to have a cached fetched. And you could whatever you want for that cache. Yeah, RQ is good stuff. But I think having a general way to handle promises in the framework seems like a good idea overall.
@o_glethorpe
Ай бұрын
0:30 I thought React 19 was created to solve exactly this kind of problem. They just can't make React not suck. Will try again when 20 comes out.
@jherr
Ай бұрын
You might be thinking about server components. And server components do this just fine. But server components can't have state, or be run directly on the client.
@o_glethorpe
Ай бұрын
@@jherr Hi, thank yout for the video, I was talking about client side, in the first 40 seconds of the video, you describe what is to me the logical way of doing this, and react being react, you need to "work around" to prevent that, the logical way, to create issues. I mean, came on, they say the problem is me, I dont have the right mind-set to work with react... maybe they are right, as a software developer, if the logical way of doing something is not the right way to do it, then this is not for me. I think I will keep trying tho.
@tnsaturday
Ай бұрын
React 19 is to solve rerenders problem by automatically using useMemo, useCallback and memo. It's not about async components. That's what Next.js is all about.
@jherr
Ай бұрын
@@tnsaturday Just to clarify. The React Compiler isn't part of React 19. It was launched around the same time, which has led to some confusion. But React 19 and the compiler are two separate things. You can actually use the compiler with 18 if you shim one simple hook. Also, the React compiler doesn't "solve rerenders" since rerenders are a critical part of the React component lifecyle. It does create code that has more optimized re-rendering and which will avoid unecessary re-renders of portions of the component. The point about sync/async component was to distinguish that I was talking about using `use` in the client context. Either as as a SPA, or as a client component in a NextJS app. These issues don't apply to NextJS in an RSC -> client component context because async requests are inherently hoisted into the RSCs in that architecture.
@tnsaturday
Ай бұрын
@@jherr Thank's a lot for clarification!
@versaleyoutubevanced8647
Ай бұрын
I'm some of the folks that like these type of content ❤
@ryandsouza2962
Ай бұрын
Amazing vid! This make s my decision of going with Astro and HTMX even stronger
@AsifMushtaq-k6b
Ай бұрын
How long we are going to learn React? Is it's a matrix lol
@Grow.YT.Views.246
Ай бұрын
So much value!
@mueslirieger
Ай бұрын
Man, I love your videos. Even though I'm currently more focused on development with Nuxt, I usually use your videos to keep up to date on React stuff, and I gotta say, your videos never disappoint. They are so informative and your presentation is neither distracting nor boring. This is simply the best React content there is imo
@derekpowersblight
Ай бұрын
I "Promise All" these work :P
@adityatiwari811
Ай бұрын
Good one. Thanks!
@bigmistqke
Ай бұрын
I don't really understand the design decision behind why use is sequential. Why wouldn't they simply collect the promises during mount and then resolve them in parallel 🤔I suppose they can't attach it to the fiber because it's not really a hook? But then maybe keep the hook rules for use? Add a dependency array if u want to conditionally fetch, tanstack query style?
@jherr
Ай бұрын
That’s just a natural outcome of JS executing this component function and use throwing a promise until the promise is resolved. That throw halts the execution of the function as any throw does. If they didn’t throw then 1) react would know how to track the promise that needs to be resolved and 2) if you had multiple uses with logic in-between that logic would need to be safe to handle undefined values while the promise is still in flight.
@SebaKerckhof
Ай бұрын
Remember how the promise of react was that functional components would be easy to reason about. It's one giant clusterfuck of a footgun by now.
@elraito
Ай бұрын
I cant explain exatcly why but with all these intrinsic sort of "rules" you need to know just keep muddying react. When thet introduced hooks i wasnt able to see why it was necessary at first but started to like the patterns on time. I hope the same is happening now when it finally "clicks" i eill actually like the new rules
@fexxix
Ай бұрын
From this video I have learned that react-query is here to stay for a very long time
@thisweekinreact
Ай бұрын
Interesting and surprising behavior 😮 Couldn't this be considered a React bug or temporary limutation? Is there a reason for reexecuting the useState init? Looks like the previous/initial result could be reused.
@jherr
Ай бұрын
I believe this is a temporary limitation meant to be a cautious step to supporting this async behavior that is still 100% compatible with the original behavior. Basically if you use the new feature, then you flip into this new mode, and if you don't then you stay in the original mode with 100% compatibility. And the downside is this state reset, which, if you code your components correctly with hoisted state, then you won't even see it.
@thisweekinreact
Ай бұрын
@@jherr I'm not sure about the "mode flipping" framing. I may be wrong but to me it's not really a mode, but just that calling "use(unresolvedPromise)" would throw a promise If you use a Suspense-enabled lib like React-Query, wouldn't this give you the same behavior?
@jherr
Ай бұрын
FWIW, I did talk to folks on the React team and there is a "mode". Yes, use throws, and that stops the execution. But if "throw === state reset" then we would expect that if you have useState, use, useState, use, that you'd get two state resets, but you don't. You only get one, and only one. And once you are in the "use" mode you are good from then on. Using RQ kind of fixes this for the same reason that hoisting fixes this since the RQ cache is an implicit hoist. RQ will give you back the same cached promise even after the state reset. The issue here is with creating the promise in the component as state, either with useState or useReducer. If you create it in the initializer then you will genuinely get a fresh new promise because the original state is discarded. The easiest "fix" for use(fetch) is to do use(useState(() => fetch())[]). What this video shows it that you'll get a double fetch if you do that, and why. :) Thanks for watching and supporting first party original content. I really appreciate what you do.
@thisweekinreact
Ай бұрын
@@jherr Sure 👍 thanks for producing it in the first place Thanks, didn't know about that mode!
@jherr
Ай бұрын
@@thisweekinreact From the conversation, it's a transient implementation detail that may or may not be there in the future. Just write your code correctly (i.e. hoisting either to a parent component or a query cache (RQ)) and you probably won't even notice it.
@MrJettann
Ай бұрын
Awesome as always, Jack! Will your course be available any soon?)
@jherr
Ай бұрын
I certainly hope so.
@aurorasofie
Ай бұрын
Hi Jack, what is the case where we would have to worry about this? Considering the use hook is meant to be used with promises created on the server.
@jherr
Ай бұрын
Where do you get that "meant to be used with promises created on the server"? Looking at the documentation, for RSC client components using RSC with suspense and client component using use is preferred, but that doesn't mean that `use` is exclusively for SSR setups. It works perfectly fine in SPAs, and Suspense is just as useful in the SPA context as it is in SSR applications.
@aurorasofie
Ай бұрын
@@jherr in the React docs the second use case of “use” other than reading a context is under “streaming data from server to client”, I don’t see any example there of other use cases. What benefits do you get from using it in a SPA?
@jherr
Ай бұрын
@@aurorasofie That example is just showing that in the context for RSC -> Client component rendering that you'll get a streaming behavior where the connection is held open until the data is available and then when it is the hole in the VDOM is filled with the new component. That doesn't mean that its the only thing you should use it for. In the case of a SPA it's a very elegant way of managing the request flow showing placeholders (probably skeletons) until the data is available.
@aurorasofie
Ай бұрын
@@jherr In practice, would that mean moving your data fetching one level up from the component to suspend it? Like with RSC and client components. Wouldn’t react query still be a better option?
@jherr
Ай бұрын
@@aurorasofie You can think of it that way, you can also think of it as moving the rendering down one layer and separating the concerns of data fetching and loading state/data state rendering. You can think about RQ in the same light; what advantages, in the simplest case, does RQ offer over this? Sure I can think of a lot of cases where the extra functionality in RQ is not modeled here, but in the case of simply fetching data for rendering, there is no inherent advantage to using RQ, you're just adding more JS to your app. The React team has added first class support into the framework for managing promises. That means that we can, in many cases, remove the code that was previously handling promise management in favor of the new model provided by the framework itself.
@peterjatek365
Ай бұрын
Thnx for the video, you are great! What happened, why don't you use typescript in your projects currently?
@jherr
Ай бұрын
Oh, for that video, the types weren't out for use, etc. I normally do.
@SteveCrozier
Ай бұрын
What do you mean by "you can't have async components on the client"? I assume I'm missing some context here.
@jherr
Ай бұрын
Component functions that execute on the client can't be `async` functions. React Server Components (RSCs) can be async functions. But they can only run in RSC contexts (primarily on the server.)
@SteveCrozier
Ай бұрын
@@jherr Oh, right. But you can put that fetch in a useEffect hook. Is there a reason not to do that? We do that all the time to fetch data for a component.
@jherr
Ай бұрын
@@SteveCrozier Of course. But this just gives an alternative workflow to that. You can put that fetch promise in useState, then send the promise to a sub-component, wrapped in a Suspense, and the sub-component can then use the `use` hook to grab the data once it's available. And then you can use use the `fallback` property on the Suspense to put in whatever placeholders you want. And that code is roughly symmetric with what you'd do if you were using RSCs. Though in the case of an RSC parent component you would just have the fetch with no useState.
@SteveCrozier
Ай бұрын
@@jherr Hmm. Not sure I understand the advantage to what seems like a lot of extra, fairly complex code. I would just use some simple conditional logic to insert placeholders. But I haven't dug into Suspense much, tbh. I may well be missing the point.
@jherr
Ай бұрын
@@SteveCrozier I wouldn't discount it out of hand. The React team has created a great platform. It's worth keeping an eye on what they are adding to the platform.
@DihCpsPsy
Ай бұрын
Is there a date to when Pro Nextjs will be available?
@jherr
Ай бұрын
Unfortunately I don't have one, soon I hope. I put a ton of work into it and I can't wait for y'all to see it.
@DihCpsPsy
Ай бұрын
@@jherr , yeah that will be very interesting, looking forward to it!
@readDocs
Ай бұрын
Also, if you want to extract the use() logic in a separate hook that you name usePromiseData for example, you won't be able to call it conditionally but use() can. You should call your function unwrapPromiseData instead. I think this API should have been called something other than use, since it doesn't follow the rules of hooks per se.
@jherr
Ай бұрын
I think you can call it conditionally, though I haven't tried it. React doesn't know you are calling a hook function versus any other function. The linter might yell at you though. But it'll still work at runtime. And yes, you could avoid the linter issue by calling it something other than `use*()`.
@readDocs
Ай бұрын
@@jherr My bad, you're right yes it's a linter issue. Still, I think calling it 'use' isn't ideal. I love the new react 19 features, but the naming of some of the new stuff is confusing at first. ('use client' for 'use client portal', 'use server' for 'use server function', 'cache' for 'dedupe' and 'use' for 'unwrap'...)
@jherr
Ай бұрын
@@readDocs 🤷♂ naming stuff is hard. I don't envy them that.
@evolopterus
Ай бұрын
Is this as big of a deal as the previous hooks drama? useEffect has not been particularly loved by many, and it seems there were too many gotchas and ways things went wrong. Is this the same deal all over again? It's important that React steers towards a direction of being simple and predictable, with little room for screwups that are not immediately obvious.
@jherr
Ай бұрын
No. This is just some small transient behavior that may change that if you were to encounter it then you might be confused. So this is letting you know that it’s out there.
@xdevchris
Ай бұрын
1+2+3 = 7 ?? maths aren't mathing dude
@jherr
Ай бұрын
I reference that a little after, and explain why it is 7 and not 6 and then get it to be 6.
@xdevchris
Ай бұрын
@@jherr yeah I know, just wanted to do this joke :3 really useful content
@jherr
Ай бұрын
@@xdevchris Hahahah, no worries. Glad you like it.
@georgios_georgiou
Ай бұрын
dang ! second here
@SeanCTTR
Ай бұрын
I don’t understand this at all. This sounds much worse than every alternative.
@YourAdamDriver
Ай бұрын
For me it looks like an awful api decision by the react team to create this `use` hook. It has way too many responsibilities
@jherr
Ай бұрын
Adam, you should use your force powers to look inside use to see that it's one and only responsibility is to monitor a promise.
@YourAdamDriver
Ай бұрын
@@jherr It has at least two: readContext and useThenable. Anyway, I don't find it convenient to use for promises. And we already have another hook to get context values
Because in the second variant it will fire a new request each time the component rerenders, but in the first it will be fired only once as it's passed to useState as default value function which is executed once
@jherr
Ай бұрын
If you just have the bare fetch then `namePromise` will just resolve and ... nothing. You have to set some state in the component to get the component to re-render. So you'd have to have this: fetch(`/name.json?${Math.random()}`) .then((res) => res.json()) .then((data) => setName(data.name)); }); Which is problematic because when the component re-renders it will start the fetch again. Which will in turn set the name, which would normally re-render, but in this case because the name is just a string and the string is the same between the first and second fetch, then you won't get an infinite loop. But that's only because the example is super simple.
@MrZiyak99
Ай бұрын
@@jherr thanks. i understood the rendering infinite loop part but I' m now confused on why a regular named promise won't do anything after its resolved. won't the use hook take care of that? or does it only take care of it when inside a useState
@jherr
Ай бұрын
@@MrZiyak99 Your second example is just a bare fetch. There is no use. Neither of your examples in your comment shows a use. Please give me an example that shows a use and I'll tell you why it does, or doesn't, work as expected.
@MrZiyak99
Ай бұрын
@@user-iv7ci3hp2u i think there is more to it check @jherr comment cause otherwise feel like we could also do const namePromise = React.useMemo(() => { return fetch(`/name.json?${Math.random()}`) .then((res) => res.json()) .then((data) => data.name); }, []); but i feel likke it wont work from what i can understand from @jherr comment
Пікірлер: 87