Relaying with SWR
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Blazing Fast Next.js with React Server Components course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Blazing Fast Next.js with React Server Components, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:11] We have seen that client-side data fetching and rendering leads to a slightly more interactive user experience. If they switch tabs, they will automatically see new values even if they don't refresh the page.
[00:12 - 00:20] But we have two problems left. First, if the user stays on the page and other people in the world are updating the value, they won't send them. That will be solved with polling.
[00:21 - 00:36] Second problem, the server-render is not displaying the right values because we are just using the client-render, so we have to wait for the application to be loaded to get the actual value after an API call. This issue is what we call "cascading".
[00:37 - 00:43] You have a lot of network requests that are fired after the page is loaded. You have to load the component, then fetch data.
[00:44 - 00:48] Maybe it will load another component that will fetch data. You have a cascade like that and it's not good.
[00:49 - 00:50] It's not very efficient. We can do better.
[00:51 - 01:01] And the solution is server and client-relaying. You might think it's not that important because in the end, when we look at the website, we have the value almost immediately.
[01:02 - 01:12] If I reload, I just see a tiny flash of the 1 value, which is the default value because I don't want to show zero customers. And then I have my value.
[01:13 - 01:16] It's really difficult to notice. Okay, I could display your loader or something.
[01:17 - 01:21] It wouldn't be a deal even though it's not that clean, but... Okay.
[01:22 - 01:28] But the thing is that some users might have disabled JavaScript. And we have seen that our website works without JavaScript.
[01:29 - 01:42] That might not be a big deal in many applications, but still, we are not respecting one fundamental idea of the web, which is progressive enhancement. The systematic reliance on JavaScript to make website works is not a good thing .
[01:43 - 01:57] It's not how the web has been designed initially, and it's excluding many users with poor quality devices, with poor connections, and with accessibility issues . We can do better than that.
[01:58 - 02:16] In terms of code, relaying is not very complicated because in SWR, we are just using the "fallback" option. If I uncomment this line, we will use the initial count as the fallback value for count that we get from the API.
[02:17 - 02:42] The idea is that while SWR is calling the API and waiting for the response that might take a few milliseconds, it will use the statically rendered value. This way, the server-side-rendered value is up-to-date, and then client-side can take the relay to update this value on user interaction, or with polling automatic. Let's rebuild the application to see what happens.
[02:43 - 02:54] So, now, if I take a look at the network tab, refresh the application, check the first request that is the request sent by the browser. I see 13 customers.
[02:55 - 03:09] And then later on, I see an API code that also gets 13 customers. You see that it happens quite later because I first need to load the application JavaScript, to execute this JavaScript, and then it will actually fire the request.
[03:10 - 03:24] So it happens much later in the process, but it lets me get fresh value using JavaScript without needing a refresh. So if I open the other tab and preorder, open the tab again, cool, I see 14.
[03:25 - 03:34] There is a small flash because it updated the static value that was 13 to 14. And thanks to revalidation, now the server-render when I refresh is also up to date.
[03:35 - 03:56] So basically, we are combining those two rendering approaches to get always fresh values in multiple situations, and to prevent the user from seeing no data or load there while the most up-to-date value is loading. We still have one final issue if I just stay on the page. Just stay here.
[03:57 - 04:01] I'm hesitating. I don't know if I want to preorder the project.
[04:02 - 04:06] I don't know anything. I'm just on the page wandering, moving my mouse.
[04:07 - 04:11] I don't know if I want to preorder. The problem is that the value will not be updated this way.
[04:12 - 04:27] It's only updated refresh the page, thanks to static rendering and revalidation, or if we switch the tabs. Thanks to client-side data fetching and rendering and SWR capacity to detect a tab being for custom gain and fetching new value in this game.
[04:28 - 04:35] What we need to eventually solve this issue is polling. It's a very simple pattern to simulate real-time updates.
[04:36 - 04:45] In the code, again, it's only a tiny option, we just have to enable the refresh Interval option. The name of this option is explicit.
[04:46 - 04:51] It refreshes the data on an interval. So here, every two seconds, it's in milliseconds.
[04:52 - 05:03] Let's rebuild the application again to see this update. Let's run the same experiment again, preorder the product, 15, and I see the 15 products, okay, like earlier.
[05:04 - 05:12] But now let's take a look at the network tab. Every two seconds, we are going to see a new request to the API to get the new count.
[05:13 - 05:26] To demonstrate what happens, we are going to need two browsers side-by-side. We cannot demonstrate this using tabs because SWR interferes with that because it refreshes the value already when we switch focus.
[05:27 - 05:32] So we need to keep the focus on both pages to demonstrate what happens. So let me open Firefox.
[05:33 - 05:42] I'm going to preorder using another browser to simulate having two users navigating on the website. One is preordering and the user should see the new preorder on the page automatically.
[05:43 - 05:50] So I'm going to preorder. And I got my update on the Chrome page.
[05:51 - 05:58] Thanks to polling, my user will have fresh values without doing any action. This use case is a bit cynical.
[05:59 - 06:04] I'm setting up a call-to-action to put pressure on the user. Hopefully, there are more interesting use cases.
[06:05 - 06:16] For instance, you could have a support chat that is updated regularly to simulate a real-time connection. Not that polling is not exactly real-time because there is no persistent connection.
[06:17 - 06:35] To achieve that, you would need a socket or tools specialized in actual real- time, which needs a lot more infrastructure than polling, because you have to set up a persistent connection between the server and the client, that's a bit more complicated. So here we have an approximation of real-time that works for many use cases.
[06:36 - 06:53] Another one would be creating a dashboard that displays up-to-date values regularly without the user having to click refresh or switch tabs so that they are able to monitor their server's performances, for instance, or their bank account or their company revenue. There is one final catch.
[06:54 - 06:59] The fallback value is used by SWR only before the first request. Then it's not used anymore.
[07:00 - 07:14] And the problem is that we might end up with a server value that is more up-to-date than the client-side value if we are between the polling interval. When I clear there, I need to wait for the next polling call to update the value.
[07:15 - 07:20] So if I'm lucky, I will see the value immediately. If I'm not, I won't see it immediately.
[07:21 - 07:29] See, this is because I need to wait for the fetch call to happen thanks to polling. We can do better than that using the "mutate" function.
[07:30 - 07:41] When we submit the form, we can tell SWR that the data fetched on this URL are not up-to-date anymore. And that it needs to get new data.
[07:42 - 07:48] And when it gets new data, it will use the fallback. So we get the server data immediately on the local machine.
[07:49 - 07:54] This will give the proper user experience. The user will see the up-to-date value immediately.
[07:55 - 07:59] And then the client-side will relay. We are basically doing the same thing as we did for the first request.
[08:00 - 08:05] We are just resetting the whole form. So we have the relay happening again.
[08:06 - 08:11] Let me rebuild and give it a shot. No, when I preorder, I will always see the fresh value immediately.
[08:12 - 08:18] I will see my own preorder immediately. Other users will still have to wait for the polling to happen.
[08:19 - 08:22] But they won't care because they are not with me. They don't know that I've updated the value.
[08:23 - 08:27] They are not in the same room. So for them, polling will be used to update the value.
[08:28 - 08:36] But me, when I preorder, I want to see the value immediately. So I'll be able to see that thanks to the mutating call.
[08:37 - 08:45] Perfect. Thanks to those little tricks, we are not able to mix static rendering to get a value from the server without using JavaScript.
[08:46 - 08:57] That displays instantly. And then having the client to make this value more interactive to make it update in real-time or almost real-time, even if other users are triggering an update.
[08:58 - 09:05] I don't need to refresh my browser to get new values. In this module, we have learned to mix client-side and static rendering.
[09:06 - 09:15] In the next module, we are going to learn how to mix dynamic and static rendering thanks to a new feature from Next.js 14, which is called Partial Prerendering.