Will React's New Cache Fix Its  Use  Hook?

Will React's New Cache Fix Its Use Hook?


Will React's New Cache Fix Its Use Hook?

Can React 18’s new cache function save the use hook and give us the use(fetch()) pattern that we didn’t ask for and probably won’t use instead of react-query or SWR?

Code: https://github.com/jherr/nextjs-react

👉 I’m a host on the React Round-Up podcast: https://devchat.tv/podcasts/react-rou
👉 Don’t forget to subscribe to this channel for more updates: https://bit.ly/2E7drfJ
👉 Discord server signup: https://discord.gg/ddMZFtTDa5
👉 VS Code theme and font? Night Wolf [black] and Operator Mono
👉 Terminal Theme and font? oh-my-posh with powerlevel10k_rainbow and SpaceMono NF

0:00 Introduction
1:21 Project Setup
2:50 Using The Use Hook
5:53 Trying Out Cache
8:39 Caching Fetch
10:22 Sharing The Cache
13:46 Bringing In Context
17:12 Architecting Around Cache
18:26 Summing Up
19:26 Outroduction


Content

0.233 -> With React 18.2 and NextJS 13 we got a new “use” hook
5.3 -> and with it the potential of doing something cool like this
8.766 -> inside of our data fetching components where we just put a fetch inside of a use.
14.166 -> Just like that.
14.966 -> And then use, which monitors promises,
18.033 -> will give us our data and that makes our components super clean.
22.633 -> But what I tried to do that back a couple months ago, this particular code
27.466 -> would cause an infinite loop of requests immediately and render nothing.
32.7 -> And when I put that into a video, folks said, oh wait, just you wait.
36.533 -> There's going to be a cache function that comes out in React
39.633 -> and it's going to fix everything and give us this cool use fetch pattern.
44.166 -> Well, cache is out, so let's go into NextJS 13,
49.2 -> try it out and see if it actually does fix this
52.866 -> and in the process get a really interesting new way of again,
56.833 -> sharing data within our React tree between components in different spots.
62.033 -> Oh, and by the way, before I forget, I just want to say thank you
65.033 -> to the NextJS team who stepped up on Twitter
67.3 -> to help me out yesterday, walk through some of these issues.
69.9 -> I really appreciate that. Thank you so much for that support.
72.633 -> All right.
73 -> Let's jump right into it.
78.666 -> This isn't going to be one of those videos
79.933 -> where we make some cool new project in this one.
82.1 -> We're literally just going to look
83.266 -> at the primitives of stuff and see how it all works.
86.466 -> So to do that, we're going to need a NextJS 13 application.
89.4 -> So I’ll create that using npx, create next app with nextjs-react-cache
94.233 -> as the name that's going to be the name in GitHub, in the link in the description
98.366 -> right down below.
99.466 -> So you can get access to all that source code of course, for free.
102.933 -> And we want to
103.533 -> use the experimental app directories so you get all the cool new stuff.
107.4 -> All right, let's try this out.
108.9 -> TypeScript, eslint, src, yes, please.
111.166 -> And the import alias,
112.233 -> which is going to give us @ slash, and that is the import for source.
116.8 -> So anything after that and you get a src file.
119.733 -> Cool. Awesome.
121.833 -> Okay, let's bring that up in VX code.
124 -> Now we are going to be doing a lot of fetching in this one,
125.833 -> so I'm going to go create some data over here in public.
128.366 -> I've got three different customers 1.json, 2.json, 3.json
133.566 -> that have some fields in them first name, last name, job, email and so forth.
138.5 -> So this is what we're going to get by just doing /1.json in the code
144.166 -> and also I've gotten some feedback that folks don't like it when I switch
147.266 -> between a black VS code and a white browser screen.
151.666 -> So I'm going to go and put in some CSS it's going to make it nice
154.8 -> and dark for us.
159.2 -> All right, now I'll go over to page.tsx and pair that down
162.3 -> to just the basics.
167.633 -> Now, this is a React Server component.
169.266 -> You can't use hooks in a React Server Component and we want to use the use hook.
173.133 -> So I need to turn this into a client or hybrid component,
176 -> whichever way you want to say it. To do that, I need to say use client
179.966 -> and then I can bring in the use hook.
182.866 -> All right, let's fire this up.
186.866 -> All right.
187.1 -> Now, that's on point 3000, which is good to know.
190.6 -> And it got a nice blank black page. Cool.
193.166 -> All right.
193.4 -> So now we won't get that nasty flickering back and forth. So.
197.133 -> Okay, so we're going to get data
200.7 -> from use
202.8 -> and use is going to use a fetch
207.2 -> and we'll go and get number 1.json
210.2 -> and then we'll put that out as data.
216.233 -> Okay, let's check.
220.5 -> Nice.
221.066 -> Okay, so let's go check it out the network and see what's going on.
225.333 -> If I refresh, you can see that we have 1.json that's really cool.
229.566 -> So what's happening here is the NextJS has wrapped the native fetch
234.3 -> and replaced it with a fetch wrapped in cache
239.666 -> and we'll get into what the cache function is and how it works.
242.833 -> And that's something to know, apparently it is an opt out thing.
247.433 -> So you can not do that if you don't want their cached version of fetch.
253.166 -> But here's an interesting thing.
255.266 -> If I go back over to the code
257.766 -> and let's say I make
258.566 -> one little change adding a query parameter on there, right?
262.4 -> This is no problem.
263.633 -> We're still going to get back to the data.
265.6 -> I’m gonna hit save.
266.166 -> If I go back over to Arc.
269.1 -> We can see. Boom baby!
272.533 -> Infinite loop requests.
276.033 -> Not great, right?
277.633 -> So this is exactly what we were seeing before with the old use.
281.166 -> I'm going to actually go back over into my Visual Studio code and disable
284.633 -> this as quickly as I can, so don't take down my browser.
292.333 -> So what happened?
293.066 -> Well.
293.266 -> What happens is every time we render home,
296.466 -> we get a new promise reference coming out of fetch.
302.466 -> And then the then and that goes off to use.
306 -> Use says, oh, I have a different promise now, so I’m gonna await that.
310.4 -> And then we would then render and then that
315.066 -> promise resolves.
316.533 -> We get data again and then that starts a re-render cycle again.
320.7 -> And so we get an infinite loop of request
323.966 -> because yes, the fetch is the same, but the promise reference
328.766 -> coming back is different each time and therefore we get the infinite loop.
332.433 -> If you're new to this channel, you probably haven't heard me
334.233 -> say this before, but references and understanding them is key
339.3 -> to understanding JavaScript and TypeScript and React.
343.033 -> It's never about the content of the array, object, or function or promise.
347.566 -> In this case, it's about the reference to it.
350.7 -> So I think we can fix this with cache, but that's because I know what cache does.
354.866 -> Not sure you do.
356 -> So let's go through what cache does. Let’s bring it in.
359.966 -> So cache takes a function.
361.966 -> We'll create a new function that is called adder.
365.2 -> It's going to take two values
368.4 -> A and B and add them together.
371.366 -> And you know what?
371.833 -> Let's just do that a bunch of times.
377.5 -> We'll do one, two, three, four,
381.2 -> and five, six, and I'll hit refresh.
384.7 -> And so I have 3, 7 and 11 over the browser.
387.166 -> Cool.
388.966 -> And let's put in a console.log here
390.666 -> so we can see how many times it was actually run.
395 -> All right.
395.266 -> So using the free VS code extension console ninja, I can see that
398.533 -> we got three invocations here,
401.7 -> one for 5, 6, one 4, 3, and one for 1, 2.
403.5 -> Exactly as we would expect. Awesome.
406.333 -> So let's try this again.
408.366 -> Let's do a bunch of these and let's save.
411.033 -> That's going to cause Arc to refresh, which is going to make the request again
414.4 -> is going to generate a console.
415.466 -> And we can see now that we got 12 requests,
417.633 -> I guess I copy and pasteed that three, four times, whatever.
421.033 -> And now we have 12 of them.
422.233 -> All right.
422.666 -> So if we were to take this function now and wrap it
426.266 -> and cache,
429.766 -> what we expect is to go back to three.
433.2 -> So what cache does is it takes a function and it returns a function that wraps it.
438.933 -> And for every invocation,
441.166 -> it looks at the incoming arguments in this case like one, two, whatever,
445.733 -> and it looks to see, have I seen that before?
448.2 -> And if it has seen it before,
450.666 -> then it returns the value that it has stored from before.
454.466 -> If it hasn't seen it, then it runs it, stores that value and returns a new value.
459.2 -> And that way we should only get three invocations here.
462.433 -> Let's try it out.
464.266 -> There we go.
465 -> Three. Awesome.
466.366 -> So what we now have in React
469.066 -> cache is a very standard
473 -> memorization function
476.066 -> in this is where we get into the world of naming
480.166 -> because we had a memo function and now we've got a cache function.
485.766 -> Except that the memo function wasn't really ever a memoization function.
489.566 -> It was a way to mark components as kind of memorized,
493.3 -> except that it was only a one level memo.
495.9 -> This new cache is actually a true memorization,
498.766 -> and the original memo is more like a cache.
501.366 -> And, ahhh. Okay.
504 -> Anyway, we just have to know that this is what this does.
508.433 -> Cache takes a function and returns a memoized function.
512.333 -> Sorry. Naming.
515.066 -> But we don't care about adding numbers together.
516.6 -> Do we? So let's get rid of this at our stuff
520.166 -> and let's go and wrap
521.733 -> our fetch in this cache.
525.9 -> So we'll call this fetch user
528.2 -> and replace the contents here
531.233 -> with our fetch.
532.866 -> We'll take an ID
534.6 -> which is a number,
537.3 -> we'll turn that into a string template
540.666 -> and we'll use that ID
542.466 -> as the number for the request.
546.1 -> Okay. Looks pretty good.
548 -> So now let's go back and try this out and see if we blow up again.
552.666 -> So uncomment this
556.1 -> and then bring in our fetchUser.
558.833 -> You have an ID, 2, in this case.
562.533 -> Now we've got our data and let's bring back our JSON.stringify. If I
567 -> okay, looks good
568.366 -> and let's inspect that, see, let’s go over to our network
571.933 -> and now we only get our 2.json request once.
575.566 -> That's really cool.
576.833 -> Originally when we were looking at this, we got that JSON request twice
581.1 -> and that's because we are in the strict mode
583.933 -> and we're getting mounted on mounted and re-mounted on the client.
586.8 -> So now we're not only just getting one request,
591.1 -> but we're actually getting one request really even with really strict mode.
596.3 -> Okay, let's try and do my little thing here where I add on the query parameter,
600.6 -> see if that hurts it.
602.066 -> I hit save.
603.033 -> Go back in Arc. Nope. Looks just fine.
606.3 -> Solid as a rock.
608.266 -> Yes, I love it.
610.133 -> Except that we've had to do the work. So. Yes.
612.6 -> Did cache save use?
616.166 -> I guess.
617.8 -> Okay. Anyway.
619.033 -> All right, movin’ on.
620.933 -> So what I want to do is I want to have two different components.
624.166 -> I want to have FirstName and I want to have LastName.
626.5 -> First, in this case would show Jamie, last in this case would show Lee.
631.133 -> And I want to get it from a single user.
634.2 -> So how are we going to do that?
636.4 -> Let's go and build our components first.
639 -> Okay.
639.3 -> New directory components
641.6 -> and into the first name component.
645 -> So we're going to get some data somewhere.
646.733 -> Are we getting an ID and we got to get that data.
649.533 -> So let's go and bring that in from Page.
652.7 -> We’ll just bring the whole thing in. Cool.
661.433 -> So now we have basically exactly it was on page.
663.9 -> So the we have first name now and we're only looking at the first.
667.9 -> All right, let's go and bring this into our page.
679.233 -> And we got to give it the ID
684.1 -> and there we go.
684.9 -> Cool.
685.333 -> All right, let's go and do the same thing for last name
694.466 -> and we'll go over
695.266 -> and bring it in.
702.9 -> Awesome. Ops.
704.133 -> Still says “First”.
706.033 -> Okay, let's go back over here to our last.
709.166 -> All right. So that worked. Well, we are getting two requests.
711.833 -> So why is that the case?
712.766 -> Well, what the deal is, is you might be like,
716.566 -> well, wait a second, They're working off the same cache function, right?
720.766 -> No, they're not.
722.333 -> They're not working of the same cache function
723.8 -> because we're creating fetchUser here and we're creating fetchUser here.
728.6 -> They're exactly the same implementation.
730.533 -> They're not the same reference.
732.833 -> So what we need to do is have them share the actual fetchUser function.
738 -> So let's go do that.
740.3 -> So I'm going to go in and extract, fetchUser here
742.566 -> into a lib directory.
746.666 -> Well create
746.966 -> new file in there called fetchUser
751.5 -> need to bring in cache
754.8 -> and export that.
757.6 -> Okeydokey.
758.466 -> Let's go over here,
763.333 -> get rid of our fetchUser
769.5 -> and then also bring in here for first name.
773.366 -> Awesome.
774.066 -> Now let's try it again
776 -> and now we get a single request
778.1 -> because we're using the same that user in both places in there.
782.033 -> Cool though.
782.9 -> So here we go.
783.9 -> Let's go back and take a look at the code we've got up here, the page directory.
787.5 -> We aren't sharing any anything between these two.
791.433 -> There's no global store manager.
792.666 -> There's no context. There's none of that.
794.933 -> And yet we're set making a single request,
798.2 -> but getting back data that runs both of those components.
802.866 -> And it's a new way to think about sharing state
805.433 -> in different parts of the React Tree,
808.366 -> where we used to use something like a global state manager or context.
812.1 -> Now we can think about just having a shared cached
816.366 -> API request system where it just dupes the requests automatically for you.
823.2 -> How cool is that?
824.9 -> But what if we want to add up here
827.4 -> to not actually have to pass in ID?
830.3 -> What if we wanted to actually have that be through context?
834.166 -> Really.
835.366 -> So let's create some context so we can pass down
839.1 -> the ID to first and last name and we can kind of get the sense of
842.7 -> if you were to use context, what you now have to put into context,
846.633 -> which is less than what you had to before.
849.633 -> All right, let's go and create user ID context.
856.566 -> All right.
856.9 -> I’m just gonna bring in an implementation for us.
858.566 -> We create a context.
860.1 -> It's going to have just be the one number, the user ID and then it's going
863.7 -> to give us back a component which we can then use.
866.766 -> User ID provider, we give it the user ID, we wrap children in it
871.2 -> and we pass along value and then we can use
874.333 -> the useUserId hook to get these right.
877.766 -> All right.
878.1 -> Let's let's try this out.
884.433 -> We'll give it a user ID of 3 this time
888.2 -> and then we'll take out these IDs.
891.5 -> Now go over into our first name and last name,
894.533 -> take out the requirement for the user ID
898.333 -> and we'll bring in our custom
899.3 -> hook to get the user ID, drop
902.433 -> that in there.
905.633 -> And so here's an interesting point.
907.2 -> So user ID,
909.433 -> we default to null over in our context, right?
912.333 -> So we set up a null here and the output of use user ID
917 -> can be either a number or null.
919.5 -> So what do we do here?
921.566 -> Because we want to fetch a user. If that's no,
924.5 -> this is where one of the interesting parts about the use hook in particular
927.333 -> comes in.
928.233 -> The use hook in particular can be conditional.
931.566 -> So we can do something like this. We can say
934.866 -> we'll get the ID
936.866 -> and if there's no ID where it return null,
940.8 -> otherwise we go on to our fetchUser.
944.433 -> This would have been a no no with any other hook
947.633 -> because the rules of hook state that you always have to have
950.233 -> the same number of hook invocations on every single render of the component.
955.533 -> But the use hook actually doesn't require that.
958.666 -> So we can do cool conditional hooks like this.
962.4 -> Awesome.
962.8 -> Let's go over and just basically copy again this in the last.
966.5 -> And so there are a lot of revisions and then change that around again
969.5 -> the last name.
973.166 -> Okay, let's see.
974.6 -> Tada!
975.666 -> Works is great. And to test it out just a little bit further
978.633 -> to show you how this caching works.
980.9 -> I'm going to bring in some buttons
982.066 -> that allow us to flip between one, two and three.
985.2 -> So I need some state for that.
987.8 -> I need to have that user ID as state.
991.5 -> Start off at one, say.
994.366 -> And then I'll paste in a bunch of buttons.
996.3 -> And then one last thing I need to actually use that user ID.
999.166 -> Okay, There we go. Let's go back into Arc.
1001.5 -> Hit refresh.
1002.9 -> And we start off with Sally Jones. Awesome.
1004.833 -> So we get 1,json, 2.json, 3.json.
1009.033 -> But now what happens if I go back to 1.json again?
1012.333 -> No difference.
1013.7 -> Why is that?
1014.833 -> Well, what's happening is that cache because it's getting exactly the same
1019.2 -> ID it did before is giving us back exactly the same promise.
1023 -> And when we ask that promise to resolve, it's just giving us back that data.
1027.1 -> It is in fact a true cache, which is really cool.
1031.866 -> So let's think about this from the application
1033.233 -> architecture perspective for just a second.
1035.5 -> We have a context.
1037.266 -> That context has, in this case, just the ID of the user in it.
1041.866 -> And then we have this fetchUser which allows us to go
1044.7 -> and make that service call, but do it in a cached way.
1047.833 -> Now let's compare that to what we would have had to have done without cache.
1051.466 -> Assuming we just had context, we would have to take all of the data
1055.433 -> from this fetch user and put that into the context as well.
1059.333 -> So the context would have had a user ID
1061.133 -> plus the first name last time, email, whatever,
1063.566 -> and now we can just have the shared piece of data
1067.3 -> that one little piece of state, that user ID
1070.066 -> and when it comes to getting specific data,
1073.333 -> we can make service requests like this and be sure that they're cached
1078.3 -> and we'll always be able to get efficiency when it comes to our request
1082 -> to the server. Pretty awesome.
1083.9 -> Now if you notice, I'm not doing anything on the server side here
1086.533 -> and there actually is a bunch of stuff on the server side around this.
1091.3 -> Doesn't use “use” obviously, but does use that cache fetch
1095.666 -> in a way very similar to this.
1097.633 -> And so if you're interested in that, please put in the comment section
1100.2 -> down below that you want to see how this works on the server.
1104.033 -> In summary, we've taken a look at the new “use” hook.
1106.4 -> We’ve taken a look at the new cache function
1109.633 -> that you can then wrap fetches with?
1112.733 -> Fetch of course is wrapped, but it doesn't seem to give us
1116.066 -> that use fetch functionality that folks were looking for.
1120.366 -> Honestly, I'm not looking for that.
1121.8 -> I think I would rather use, useQuery or use
1125.533 -> SWR for that because those have extra stuff.
1130.033 -> Like did we get an error or are we still loading?
1133.333 -> The refetch stuff.
1135.133 -> All of the mutation stuff.
1136.833 -> It's just a much better interface.
1138.166 -> So I think use fetch is a cool idea, but it really only works in the happy
1142.133 -> path case and it doesn't give us a whole bunch of extra functionality.
1144.966 -> So I'm going to leave it alone.
1147.066 -> Even if we got it.
1148.333 -> But I do think that this cache
1151.366 -> used responsibly is very, very cool.
1154.466 -> I do think though that in a SPA context,
1158.233 -> when you have a long running session, figuring out how to invalidate
1162.433 -> parts of this cache is going to be really important.
1166.433 -> All right. Well, I hope you got a lot out of this.
1167.9 -> If you did, please hit that like button.
1170.433 -> If you really did, please hit that subscribe button and click on that bell
1174.4 -> and you’ll be notified the next time a new Blue Collar Coder comes out.

Source: https://www.youtube.com/watch?v=T3m-MZkuadU