I've done some work with SSR but mainly using NextJS -- I understand why the code is being rendered (first, at least) on the server (to show the user a screen quickly, to allow search engines to parse SPAs), and to some extent how it's being done (some engine on the server side will take the SPA and convert it to HTML and then sent it 'down' to the browser).
What I don't understand is what the step-by-step process of SSR entails. I've been working through a Front End Master course on intermediate React that briefly touches on Reactdomserver -- I understand the concept: convert the SPA elements to strings, and send them on to the browser. The course says that 'event listeners are added later' (I suppose once React takes over), and that render isn't available on the server. I believe I understand the second part -- I suppose the React javascript just isn't available until React is up and running -- but don't understand what the first statement regarding event listeners actually means. When I wrote old-school HTML code, loaded it to a server, and it was downloaded to a browser, complete with whatever event listeners I had, and it just worked. What is SSR doing differently than we did in the old days writing non-SPA sites? I suppose it's that the DOM isn't available on the server, so you can't add event listeners until the HTML is rendered in the browser and the DOM is built -- but as nothing is displayed until the DOM is built, why even talk about 'adding event listeners later'?
Thanks for any help you can provide!
Let's take a very contrived example React Component:
function App() {
const [content, setContent] = useState("click me!");
return <div onClick={() => setContent("you did it")}>{content}</div>
}
Now, on the server, we want to generate HTML from it. For that, we mimic useState to return the initial state, call App(), and arrive at a JSX tree that looks like:
{ type: "div", props: { onClick: () => ..., }, children: ["click me!"] }
Now we can turn that into a string of HTML easily ...
<div>click me!</div>
and send that to the client. But wait, were did the onClick go? Well, we could not add it. For sure we could (1) add an inline onclick handler, or (2) register some event listener later, but the function was instantiated on the server, we can't just serialize it and send it to the client.
<script>
getElement("App").onClick(() => {
setContent("you did it!"); // Um ... Were does it refer to?
});
</script>
Now what to do? Well, we could take the React Component again, and turn it into a piece of JS, that is intended to run on the frontend as a whole. Then we can attach that piece of JS to the HTML we sent to the client. Now we run the same code on the frontend, but this time we do have access to the DOM, we can register handlers, and we can rerender if setState gets called. Therefore App() gets called again, but from the JSX returned ...
{ type: "div", props: { onClick: () => ..., }, children: ["click me!"] }
... we can directly generate Elements now, and attach the handler:
const el = document.createElement(jsx.type);
el.addEventListener("click", jsx.onClick);
el.appendChild("click me!");
And all that is exactly what NextJS does for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With