The State of The State In The App Router

Rate this content

NextJS 13.4 changed the game with the App Router and React Server components. The change to the state management model looks simple to start, but gets complex very quickly as you try to create the practical every-day user experiences that were straightforward in the pages model. We'll talk about the different state management models, how they work in the App Router, and how to decide which you should use.

32 min
20 Oct, 2023

Video Summary and Transcription

React has improved state management with built-in hooks like useState, useReducer, and useRef. Redux can still be used but it's recommended to avoid global state. Zustand is an alternative state manager that allows for easy creation of hooks. Proper architecture is important for accessing the global store. State managers can add extra bytes to the client's JavaScript bundle, so it's important to be selective in choosing libraries. Next.js and React routers are recommended for server-side rendering and personalized experiences can be achieved with spas.

Available in Español

1. Introduction to State Manager

Short description:

I'm Jack Harrington, a FullStack engineer and YouTuber. I cover React, state management, and the AppRouter on my YouTube channel called the Blue Collar Coder. I learned from experience and feedback and will share pragmatic rules for using a state manager properly and safely.

All right. Yeah, I'm Jack Harrington. I am not just a FullStack engineer like a lot of you, I'm sure. I'm also a YouTuber. So I have this YouTube channel called the Blue Collar Coder, and on there I cover a bunch of different topics. So, a lot of React, obviously. And I talk a lot about state management. So I cover in-depth details on that, and I talk a lot about the AppRouter, because it's next to the S and it's very popular, and it's the new router, and I get a lot of feedback because I cover a lot of these things. Like, hey, how do I use my Redux store in the AppRouter? And I'm like, that's an interesting question. So I did a bunch of coding to see myself, how I would do that. And I knew at the time, I was like, hmm, this seems to work. It definitely does work, but maybe this is not the right way. So I put out a video. Boom. And it actually did pretty good. People seemed to like it on the comment side. In fact, when I took it down, because there are some anti-patterns in it, they were like, where'd it go? But I got some feedback from the React team and from the Next.js team, like, you know, there's some things you shouldn't do in there. So what I'm here to do today is to give you all of the experience that I learned from that. I went back and did a lot more coding, got a lot more feedback. And what I'm hoping to present today to you are some basic pragmatic rules around how to use a state manager properly and safely. And maybe if you should or shouldn't in the App Writer.

2. React State Management and Redux Safety Tips

Short description:

React has improved state management with built-in hooks like useState, useReducer, and useRef. Next.js also provides state management options like route state and searchParamsState. This means that you might not need a separate state manager. However, if you still want to use Redux, here's a safety tip: avoid global state.

And interesting, let's go back to beginning on this. So common thought around React has been... I mean, it's only been around for ten years. But for most of that, or a lot of that, we've had the class components, and this.state and this.setState. And that wasn't great, from a state management point of view. So that's why you run into things like Redux, MobX, to make it a better experience.

But now, you have to think differently about it. Because we've got better state management built right into React. You've got useState, useReducer, useRef to store a state. You've got useCallback, useMemo, useEffect to listen for changes in the states. And that is basically a reactive state management system built right into the core of React. So maybe we don't need a state manager.

And then on top of that, we've got Next.js, and the operator has the route state. You've got the parameterized routes, you've got the params, you've got searchParamsState. You looked at Lee Robinson, he did a fantastic video recently on how to use searchParamsState to hold state and manage state in a Next.js application. You have form state, you've got server actions, you've got revalidation, you can do things like HTMX and have server-side driven development. So end result is rule number 0, you might not need a state manager. So think about it that way first. When you think about your new project or migrating, you know, maybe a state manager is not gonna be a part of that.

It's weird. You come with a talk on state management, and I'm the guy that's telling you maybe you don't need a state manager. But maybe you're like, oh, I'm really sad. I love my state manager. I love how it works. I don't want to do dependency arrays. So OK. Let me give you some safety tips for how to do it safely if you want to use a Redux store still. So rule number 1, no global state. So what do I mean by that? Well, OK, let's think about a global. You got your configuration store here.

3. React Toolkit and Global Variable Issue

Short description:

This is React Toolkit. The problem is the global variable. In the pages writer, it's not a problem. But in the app writer, it becomes an issue with request overlap and accessing data from different requests.

This is React Toolkit. Maybe some of you are familiar with this. If you're going to use Redux toolkit, if you're going to use Redux, please use Redux toolkit.

So what is the problem with this? Well, the problem is this. The global. This is literally a global variable. And in the pages writer, this wasn't really a problem. It's a pretty simple thing. Get server-side props. Go off and do some sort of async stuff. And then eventually you just do a tree render. And the tree render is synchronous. So hey, make a store. Whatever. It's fine. No big deal.

We can get into some issues where request to request. You might have request overlap. But no big deal. App writer, though, that's a different deal. So let's say you get request one. You got a tree render. And as part of the tree render you got asynchronous components in the tree. So it goes and sets request one, sets the store to its request one. Then it goes off and starts doing some work. I'm blocked. But now the server is like, okay, cool, I'll take another request and I'll go set that store to the second state for that request. So now I've got data from the second request in memory, in the server from the first... That is going to get into the first request really easily. Because that's going to go and then access that data, like who is the current user, all that sort of stuff.

4. React Store Provider and Per Route State

Short description:

And it's going to bleed data. So that's not great. That's why you don't want to use globals. Let's do a donuts and dragoons store in the app writer. We're interested in the cart pop-up and the add to cart pop-up. Let's just use context. New school thinking, create a store provider component to avoid global space. Use a create store function to dynamically create a store for each request. Use the Redux provider and use selector for state management. Per route state introduces a specific challenge.

And it's going to bleed data. So that's not great. That's why you don't want to use globals.

So to put this in a more practical context, let's do a donuts and dragoons store. And this is gonna be in the app writer so you'll have a layout at the top that holds the whole page. You'll have a header and then a cart pop-up. You'll have the content of the page, so this is like an e-commerce kind of page.

And the ones that we're really interested in are these two components, the cart pop-up and the add to cart pop-up. Because those are client components, they're gonna mutate state, it's going to be mutable. And that's when we want to use something, maybe, like a state manager or not. Let's just use context. If you look at this and you're like, oh, that's so simplistic, all you have is a number, yeah, that's true. You know, I mean, you probably don't need to use a state manager for this, but let's just say you do.

So the old school thinking would be like, okay, so we're gonna have our global store, like I talked about before, and we'll just get a redux provider, point it at the global store, and there you go. So again, it would look like that. You'd have a provider, give it a store that you just created, and then when you want to use it, you give it a use selector or use dispatch and then you can talk to that store. New school thinking, so how do we fix that? How do we fix having that store in global space like that? Well, what you do is you can just create a new component, a new client component, we'll call it store provider, and just move that store into there. Now, for every single request, we have that store uniquely within that tree of components and avoid any kind of potential for cross request pollution.

So where we used to have something like this, now we're going to go have a function called create store that does exactly the same thing, but gives you back a store dynamically. So you can create a new one for each request in that client component, so let's go take a look at what that is. So we have a store provider, pretty simple, we're going to use a use ref to store the output of that create store, and then we'll just use the simple old Redux provider to provide that down to our components. If you have some sort of initial state, you can start off with that use ref being null, go to check to see if it's null, create the store if it's null and then initialize the store by using a dispatch. And the nice thing about that is that if you have state in here in the store provider, disassociate states, it's also doing other things, I don't know, something else like showing the menu or whatever, then you can run this a bunch of times and it'll only ever do this on initial startup. To use it, we just use use selector, just like we did before. Same thing. So from there on down, it's like just using Redux. Here it comes, though, when you get per route state. Because, something specific about this. So let's say we have our, this is our store, right? We've got two new components in there. We also want to drive the deep, and the reviews.

5. State Manager and Reviews Initialization

Short description:

We have both cart data and reviews in our store. The problem is that the reviews component gets recreated every time we switch routes. One solution is to initialize the component properly. Another idea is to use Zustand, a different state manager. Zustand is easy to use and allows us to create hooks for any kind of state. By hoisting the hook into a provider, we can avoid using global state.

So we've got, like, average reviews, got some reviews up there, and we want our store to drive all that. So we're going to have both sets of data. We're going to have cart data that needs to be at the top of the tree, and we've got reviews that is kind of nestled within the detail page, but still within the global store because we don't have a singleton for that.

So when we go from page to page to page, you can see that the only thing that actually changes is the detail page. That's really nice, from a development perspective, from a customer perspective. Obviously things aren't changing, you're not getting any flicker on the screen, that content is only changing. But it does mean that that section is changing and that one is not getting updated. So you have a problem.

So the fix for that is to see the initialization phase of every one of the components and realize that that reviews component is getting reloaded, like recreated every time you get, you switch from route to route to route. So we can do a much more convoluted but still pretty easy to understand initialization. So you get the store, you figure out whether you're initialized or not, you use a user for that and then you dispatch the reviews, in this case, the initial reviews that you got from the RSC that contains that. And then you go back and you get the reviews. It does seem like a lot of work, certainly more, a lot more work than we did with the cart. So what can we do to improve that?

So one idea is to use a different state manager all together, a state manager called Zustand. Anybody familiar with Zustand? Woo! Okay, awesome! I wish they'd picked a different name because I'm not German. But okay. It's really easy to use. So you basically create a hook using create, like this, pretty simple. You give it any kind of state you want. I mean, obviously, we've got a count here in an incrementer, the classic model of a state manager. And how easy is that? You can see why Zustand is really well loved.

So how does this change the game if we use Zustand? Well, so we got our reviews. We got our average reviews. We're going to go back to those parts of the page. And to drive those, because those are in different parts of the tree, maybe you want to have a global state manager, normally we just do something like this, we create user views just like we did before globally. But we don't want to do that, right, because we know rule number one, no globals. So what can you do with that? Well, we can go do basically the same thing. We can go hoist that hook into a provider. So now you're going to have a context, which is going to have the hook that you use. So you get the context that in turn gives you that hook, and then you can use the hook to get data.

6. Creating and Using the Reviews Provider

Short description:

We use a createReviews hook instead of a global useReviews. We recreate the Redux provider using a context, custom hook, and provider. To initialize it, we have a route RSC that makes a request to a microservice and uses the reviews provider to send the reviews down to the hooks and components. It's important to be selective about the data sent to the client. To use it, we get the reviews hook and use it.

So what you might have had before, again, you've got a problem here, you've got this useReviews that's global. We instead go and use a createReviews hook just like we did before. And let's go take a look at how that gets used.

The only gotcha here is that we don't have a Redux provider like we did before. So basically we have to recreate Redux provider. Thankfully, it's really small. So the top, you'd have your context. Basically say, hey cool. The context contains the output of createReviews hook which is going to be userReviews. We're going to have a custom hook that will get us the hook. So it's a hook that gives back a hook, a little weird but okay. And then finally we're going to have the provider. Again, it's a client component and because it uses obviously hooks. And this case we're going to use useDate to hold the data. You can use useRef. You can use useDate. I've seen both ways. I don't really have a dog in that fight so no problem. And then you give that store to our newly created provider and we pass it down.

Now to initialize it we have our RSC. So this is a route RSC. It's going to take an ID. It's going to go make some request to a microservice and then it's going to use that reviews provider that we just created to send those reviews down to the hooks and then the components.

Now one thing is really important here is, notice how I'm using as opposed to product. And this is more just in general in terms of how to use the AppWriter. Really important to look at the output of the server on every single route to see what's actually getting through because everything you send to a client component in terms of the app, it's going to get serialized into JS and sent down the wire. So if you go and send all a product but you don't actually need it, you're sending a lot more data than you need to. So be very, very selective about the data that you send down to the client. Then to use it, we just get the reviews hook and then we use the reviews hook. Pretty easy.

7. Sushant Version and Avoiding Mutable Data in RSCs

Short description:

With the Sushant version, we can have multiple stores that are co-located close to the components that need them. This avoids the need for crazy initialization code and makes passing data within the component tree easier. Rule number two is to not show mutable data within RSCs. If the data is in context, it cannot be accessed directly from an RSC.

And if you want to, you just kind of do a double call like that. You get the reviews hook back and then you use the reviews hook. Now one thing about this, I will say and I should always say about Sushant hooks is always make sure to, I don't need to do it here, Sushant will take a selector as the first argument. So you get given the state and then you return just the piece that you need. This is really important for efficiency sake. If you're not going to use context, you're going to use a state manager, please use it correctly. I need all of it here so that's why I'm just doing that. But if I only need reviews, I can just give it a function that would just return the reviews and that will make it more efficient when I need to get updated I just look for reviews. So how does this actually solve that problem that we saw with the Redux version? So with the Sushant version we can have multiple stores which makes it so much easier. We can have the cart store provided by the cart hook provider that feeds the cart pop-up and add a cart. Easy peasy. And then we've got the review hook provider that feeds just the reviews. And you can basically co-locate them as close as you can to the component that needs them. So as you navigate from page to page to page, right, the detail page gets updated each time as we go around. And that's just in that section. So that means that this reviews hook provider is automatically getting completely restructured and completely rebuilt every single time, which means that we don't have any of that crazy initialization code. We just give it the reviews. Easy peasy. So that's the easiest thing that I have found in terms of creating the store within your component tree and then passing around that data. So rule number two. And this is the one that really got me in trouble with the Versil team, was RSCs don't show data. In fact, during the presentation this morning, one of the other presenters like made this point, don't show mutable data basically within your RSCs. So what does that mean practically speaking? So let's go back to our Redux example again because, you know, Sushant, it's not like what everybody uses. So we got that cart store up there, and we got our RSCs. In this case, the RSCs are just shown with a single line, you know, the cart pop-up and all the client stuff is very large. So the one RSC is a details page, and it wants to go and get the cart store. Hey, I need to know how many things are in the cart. Here's the crazy thing, the cart store is in context, so you can't do it. You can't get there from here, and that's one of the great things. If you follow the first rule, the second rule essentially just naturally follows through.

8. Accessing Global Store and Architecture

Short description:

You can't access the global store directly due to its context. Prop drilling won't work because the store is created in the layout component and consumed in the route component. This connection between rule one and rule two enforces the need for proper architecture.

You can't actually access the global store because the global store is in context. So easy. And you're like, oh, okay, I can get around this. That seems like a limitation I can get around. I can go and just prop drill it. Sure, I'll just create it and prop drill it around. But you can't because the store is created up in the layout component and then it's actually consumed in the route component. So you'd have to prop drill all the way through, and that's not going to work. So nice connection between rule one and rule two. Rule two, just essentially is enforced by that first rule. So you get that architecture right, and it works just right away.

9. Separating Data and Choosing Technologies

Short description:

Separate mutable and immutable data. Check SSR output, route changes, and app writer caches. Use React and Next.js core mechanics. Use Next.js built-in features like route params and form state. If needed, use React context for low-velocity data. Consider using a query library.

And then rule number three, pretty easy, and it follows along again, separate mutable and immutable data. So you've got your layout, you've got your RFCs. Your RFCs are showing immutable data like the picture, the image of the dragon in this case, and the title, price description, related products. That's immutable data that's not gonna change on a per-request basis. It doesn't matter who you are, it's gonna be the same number. And then we got the client components that are showing mutatable data, the things that can actually change. So that's pretty much common sense, but it's good to talk about.

Now, in order to figure all this stuff out, I actually did create a testbed where we go through and see, what can I do with an app that could screw this whole thing up? So here are the things that I checked. So and I think when you implement a state manager in your own app, this is what I think you should check as well. Check the SSR output, make sure that the SSR output actually shows what's in the store, because if you haven't initialized it properly, that's probably one of the biggest places you're gonna find where it's missing. It's gonna be missing on SSR, but it is gonna be available on the client, and you're gonna get an issue of hydration. Check route changes. As you go from route to route to route, you're in a spa, basically. So if you don't initialize it correctly, you're gonna see issues there. So that's another thing you wanna check. And finally, as mentioned by a few folks, the app writer has a ton of caches. So well, four, and you wanna make sure that you check the mutation and the revalidation so that you're getting the right data into your store. And you'll be like, man, this is so easy before.

So how do I decide which one I'm going to use here? So in terms of the underlying technologies, I would say, first off, obviously you're gonna use React and Next.js, and I would use the heck out of the basic core mechanics of React. Use state, useReducer, useEffect. Get to know these. These are good. Once you get to understand the dependency mechanism, it actually gets you, makes it really easy to build a piece of state that's actually pretty easy to work with, and then on top of that, make sure to use the Next.js stuff that's built in. And again, route params, form state, all that. If that doesn't work, if you still have data you need to move around, put in different parts of the tree, just use basic off-the-shelf React context. And for that, I would say only use that for more low-velocity data. An example would be the user, who the current user is, the theme, things like that. The things that are not gonna change that often, unless you have somebody pathologically just logging in, logging out. Kind of crazy. And on top of that, maybe you can get by with like a query library.

10. React Query, Singleton Store, and State Sharing

Short description:

React Query, SWR, singleton store, multiple stores, mobile stores, lightweight state managers, Pro Next JS tutorial, Basic React context, Redux, Sushstan, Jotai, atomic state manager, recoil model,

React Query, or SWR. And still you haven't brought in a state manager but you're building a functional app that has everything in it. So this is kind of, as you get new features, keep on layering on new things as you need them, but don't just bring them in because you like them.

I mean, I like React Query, but you don't necessarily need it unless you need it. And then finally, there is the option of bringing in a singleton store, although, I mean as I showed, there are some issues with initializing a singleton store properly. So maybe multiple stores. Maybe use instead mobile stores like, or other lightweight state managers like, for example.

If you want to learn how to do all that, I have a new site that I'm working on called Pro Next JS. That has an entire tutorial, it's free, 100% free. You can go there right now,, and take this tutorial. It'll teach you all about how to do this with Basic React context, Redux, Sushstan, and my new favorite state manager, Jotai. Which is more of an atomic state manager kind of in the recoil model. And then of course, hey, I'm always up for a subscribe. If you want to go to at your... Alright, there you go. Alright. Thanks a lot, sir. Thanks a lot. Do you need some help? If you hold the mic then I can... Yeah, there you go. Okay. So, does sharing state via these providers force all children to be client components, even those that would otherwise have been server components? Yes. Essentially. If you're going to have any kind of state that is shared through context, it has to be available. It has to be a client component. If you think it's going to be mutable, yeah, make sure that it's a client component. Okay. Yeah. That's not necessarily a bad thing. I think there's this perception out there that client components don't SSR, which is crazy.


React State Manager and Store Provider

Short description:

They totally do. In fact, actually, when you think about it, just a pages router is essentially just all client components. No global store. Use a store provider in every child layout. Zustand and other related libraries work well with other hooks. Use sparingly as needed. Context can be used for low velocity data.

They totally do. In fact, actually, when you think about it, just a pages router is essentially just all client components, so we're basically getting the upgrade of being able to say specific components only run on the server, and those are RSCs, but otherwise it's fine, totally fine to use a client component.

Cool, thanks. Next question is from Alex. You said, no global store. You mean don't put the store provider inside the root layout. Instead, put it in every child layout. I guess? You are using a store provider. You're just not specifying it and you're not creating it as a global variable. It is still global because it is global to whatever context you put it within. Everything from that layout element down or that component down is going to have access to that. But no, it's not going to be global in the sense of a global variable, which is what you're trying to avoid because of the request issues. Okay. Thank you.

Next question from John. For now, honestly, Susan for sure. What's your opinion? For me, main reason, I want to access a muted store outside any framework to no vendor lock. I'm not sure what the question is. And honestly, just for sure, what's your opinion? All of these state managers are great. I don't see any issue with using, I mean, vendor lock-in seems odd. There's no real vendor here other than like Daishikato and it's open source project. The nice thing about Zustand and other kind of related libraries or that they really work well with other hooks. So it's not like you're taking all of the, you're not removing use state entirely, you're not removing use reduce or whatever. You're using this in conjunction with that. You're saying, okay, this particular piece of data, I want that to be global, and the other things, eh, no worries, they don't need to be global. So you know, you kind of use it sparingly as you need it and then in terms of, like you may use context as well as Zustand if that context is for things that are low velocity or are they going to be the kind of changes that you know will mean a refresh of all your components anyway? So you might as well just put it in context. It's very simple. So. Yeah. But aren't you afraid.

Redux and Context for State Management

Short description:

My wife had a hard time grasping Redux and context as a newcomer. I prefer self-contained component trees for state management. Using context or other libraries makes more sense and is more maintainable. The global store approach has no clear rules for data placement. Next.js is worth using for non-JS backends if SSR is not needed.

So I'm going to tell you a scenario. My wife. Okay, yeah. My wife is also a front end engineer. Okay. She joined the company where they were using, if I'm not mistaken, Redux and context. Like you're saying. Yeah. Yeah. But for her it was really hard to grasp as a newcomer in the project. Yeah. What is where. Yes. So with that in mind, if it's a bigger thing that you're going to be working on with a bigger team for multiple months or years. Yeah. Would you still advise mixing it?

Absolutely not. That's what really has worried me about honestly Redux from the beginning was that you're putting a lot of data into Redux and it's not always. I mean we've got slices now and so you can go and kind of partition data. But I like the idea of having kind of self-contained component trees and the idea of having a you shared piece of state management that is just within that component tree, whether it's context or whether it's Sushtan or whether it's a Jyoti space, I think was what they're called. That to me makes a lot more sense and is a lot more maintainable than having everything in one spot because then, yeah, there are no rules like okay where does this data go? I don't know. Is it supposed to be local? Is it supposed to go into context? It's supposed to go in every... Is the global store like a grab all bucket where you put chicken wings and all the rest of it? That's definitely the underpinner I've seen. I see where folks have come from when they want to use a global store where okay I will put all our data in here and then you can serialize the state and then just have it where you can just regenerate the state and that's cool. I just haven't really seen that actually in production all that much.

Okay. Thank you. Next up, question is do you think it's still worth using a React framework like Next.js if you have a non-JS backend, Java or .NET? Yeah. You're going to basically be building a spa. And I think that's a perfectly viable use case, particularly for applications that don't necessarily need SSR, right. And a lot of applications don't need it.

Spas for Personalized Experiences

Short description:

If you're running a content site, spas are very viable and portable. You can use the same spa on an Electron app and connect to your Java backend via an API. It's not recommended to make your Java backend do SSR.

If you're running a content site, obviously you want to have that. But if you're running something that's a completely personalized experience like a banking app, like I don't really want to have the issue potentially of having my particular bank account cached in a CDN somewhere where somebody else might want to access it. So I think spas are very viable and also very portable. You can use that same spa on an Electron app, or something like that. So you can then use your Java backend via an API. I wouldn't try and go and somehow make your Java backend actually do SSR. I think that's going to end up poorly. But otherwise, yeah.

State Managers and Bundle Size

Short description:

State managers are not always necessary in React. They can add extra bytes to the client's JavaScript bundle. It's important to take the time to learn and use the basic React hooks properly. Don't rush to use a state manager in small apps where useState can handle the job. Be selective in choosing libraries and consider the impact on the bundle size.

Yeah, might have been too much customization. Yeah, I think I've actually seen it before, it didn't end well. Ok, sounds like something for the after party, some war stories. Always war stories. Yeah, I love those.

Next question. Why would you... should we not use state managers? What's wrong with them, since you mentioned that as one of your first points? I don't know anything wrong with them, per se. I just don't know if they're always necessary, given the changes that we've seen in React and the power that's baked into React. I guess what would be wrong with them is the extra bytes you're sending down that you might not necessarily need to send down, just because you don't like dependency arrays or something like that. I definitely think that... take the time, honestly. One of the ways that I learned React hooks was actually to work on a project where I was restricted from using anything other than the base hooks. And that'll teach you real quick about how to use UseEddy and use effect the right way and, yeah, build out and use those basic tools the right way.

I know people come to see Jack but I'm gonna give my opinion. Yeah, yeah, please, no, no, no, go for it. What I've seen is that people grab for state managers too soon. So when your app is still really small, and let's say you're just building a menu and you want to keep the state if it's open or closed, they're gonna grab for a state manager because we learned to use Redux or whatever. While use state will do the job just fine. I think using a state manager is fine but don't grab for it immediately when your app is super small and you don't need it yet. Yeah, totally.

I run a Discord server. The Discord server has a lot of folks on it and they ask kind of general questions. One of the most common things is somebody coming in and like, oh, I've got, you know, an app that I just built that, you know, it's React plus it's Redux plus it's React Query plus it's this plus it's that plus it's that. And I'm like, Whoa! And now it doesn't boot. I don't understand. Like, okay, this is not like a, you know, just kind of a scoring thing where it's like I just need to take every single like MPM project and just drop it in there. You know, no, like be sparing. And being judicious about it, realize that like you are sending extra JavaScript down to the client for each one of those libraries, make sure that they're earning their weight, you know, and don't just bring in stuff because oh, yeah, so and so uses React Query, therefore I got to use it. Or yeah, I mean, React Query is awesome.

React Routers and Next.js SSR

Short description:

React routers and Next.js provide SSR capabilities, making them valuable for server-side rendering. If you need SSR, it's recommended to use off-the-shelf solutions like Next.js or Remix. For non-SSR applications, Veet and React are suitable options. Migrating from pages to the app router requires careful consideration and understanding of the benefits it offers, such as out-of-order rendering.

React routers and the 10 sec routers are awesome. So certainly use it if you need it. But don't just go and grab it right away.

Good point. If you need it. If you need it. Exactly. So Max is asking, you mentioned Next.js has a lot of caching, some of them with some gotchas. Now we add a store in the mix, why would I use Next.js instead of just vanilla React?

Okay, that's a good one. I mean vanilla React, you're going to have to do your own SSR, right? So that's the big value that we got out of Next.js was you got a router that gives us SSR, and really easily. And I got to say, actually if you've tried to ever do, create an SSR server, and I have, it's not easy to get it right. There are, certainly you can get off-the-shelf stuff, you can get the Veet SSR plugin, you can turn a Veet application into an SSR application. But yeah, if you need SSR I would definitely go with something off-the-shelf like Next.js or Remix is another great example. And if you don't need SSR then sure, go with probably Veet and React. Certainly not CRI.

Cool. Do we still have time? 20 seconds, really? 5 seconds. 20 seconds. We can do this. Any thoughts on migrating from the pages to app router? And issues that you can run into, share, and stay between the two? Oh, nice one. Oooh. I think the migration issue was covered a lot this morning in that talk. Yeah, I like the idea of going route by route, but I mean, honestly, the app router is such a huge change. They literally flipped the apple cart on us. And you really have to think about things. Not like, OK, I was doing this, now I'm doing that. I really think you have to spend the time to really figure out, OK, why am I using the app router for this route? What is it giving me? And in particular, I think, when it comes to the app router, what you're looking for to really leverage it is out-of-order rendering. So you want this part of the page, you can literally look at the page and say, OK, we're getting this piece of data from this microservice on the product detail page of our Dungeons and Donuts and Dragoons store. Like the product details come from this microservice. We're going to block on those, since we don't want to show anything until we have the image and all that.

Reviews Rendering and App Writer Performance

Short description:

The reviews might be a slow service, so we wrap it in suspense for a better customer experience. It works with SEO and allows the Googlebot to see the HTML. However, if you don't have microservices and can't get data from different sources, you won't get the best performance with the app writer. That's all the time we have. Thank you!

But the reviews, eh, it might be a slow service, so we're going to wrap that in a suspense and then we're going to do an out-of-order rendering on that when it's ready. And that gives a much better customer experience, like the customer gets the page right away and then later on, a little bit, they see a little spinner and then they get some reviews.

OK, cool. And it works with SEO. It actually, like if you look at the stream that the Googlebot's going to see, it's actually going to see that HTML. But if you don't have that, if you don't have microservices that are broken out that you and you can use, you can get data from here and here and here, then you're not going to get the best out of the app writer and you might not be getting as performant of a page as you would using just the page router. So it's a tough call.

All right. Well, that's super hard all the time we have. I think we did a good test for New York. Yeah, big time. I can't wait to see you there, yeah. All right. All right. Give a warm round of applause, everyone. All right. Thank you.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2023React Advanced Conference 2023
27 min
Simplifying Server Components
Server Components are arguably the biggest change to React since its initial release but many of us in the community have struggled to get a handle on them. In this talk we'll try to break down the different moving parts so that you have a good understanding of what's going on under the hood, and explore the line between React and the frameworks that are built upon it.
React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
Top Content
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
Vue.js London Live 2021Vue.js London Live 2021
34 min
Everything Beyond State Management in Stores with Pinia
Top Content
When we think about Vuex, Pinia, or stores in general we often think about state management and the Flux patterns but not only do stores not always follow the Flux pattern, there is so much more about stores that make them worth using! Plugins, Devtools, server-side rendering, TypeScript integrations... Let's dive into everything beyond state management with Pinia with practical examples about plugins and Devtools to get the most out of your stores.
React Advanced Conference 2023React Advanced Conference 2023
33 min
React Compiler - Understanding Idiomatic React (React Forget)
React provides a contract to developers- uphold certain rules, and React can efficiently and correctly update the UI. In this talk we'll explore these rules in depth, understanding the reasoning behind them and how they unlock new directions such as automatic memoization. 
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Top Content
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.

Workshops on related topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn