DEV Community

Jalaj Bankar
Jalaj Bankar

Posted on

Server Rendering, Express Routing, JSX Under the Hood, and this Keyword Finally Making Sense

A big session. React internals, some Node territory, and one of the most confusing JavaScript concepts that suddenly clicks when explained the right way. Let's get into it.

Two Types of Server-Side Rendering
These sound similar but they're quite different in how they work:
Server-Side Rendering (SSR) — the entire page is rendered on the server on each request and sent as ready HTML to the browser. Fast first load, good for SEO.
React Server Components (RSC) — a newer model where specific components run only on the server, never shipping their JavaScript to the browser at all. Not just rendering on the server — actually living there permanently. Leaner bundles, better performance.


Basic Routing in Express
Express makes routing straightforward — you define a path and what should happen when someone hits it. Learned the basics today, more on this as it gets deeper.

npm run dev vs npm run build
Easy to confuse early on but the difference matters:
npm run dev — spins up a temporary development server in memory. Nothing is written to disk. Fast, hot-reloading, meant for development only.
npm run build — creates permanent, optimised files in a dist/ folder. This is what actually gets deployed to production. Minified, bundled, ready for the real world.

Three Ways to Create an Element — JS, JSX, and Raw React
This is one of those comparisons that makes JSX suddenly feel less magical.
Plain JavaScript:
let H1 = document.createElement('h1');
H1.textContent = "Hello World";
React + JSX:
const H1 = (
<h1>Hello World!</h1>
);

React without JSX (what JSX actually compiles to):
React.createElement('h1', {className: 'greet'}, "Hello World!");
And what React actually holds in memory after that — a plain JavaScript object:
{
type: 'h1',
props: {
className: 'greet',
children: "Hello World!"
}
}

JSX is just syntactic sugar. Under the hood it's always React.createElement producing a plain object. The browser never sees JSX — Babel transforms it before it gets there.

useRef() — Reaching Into the DOM
useRef() gives you a way to directly reference a DOM element from inside your component — without triggering a re-render when it changes. Useful for things like focusing an input, reading scroll position, or integrating with third-party libraries that need a real DOM node.


useContext() — Skipping the Prop Chain
Normally if component 1 has data that component 7 needs, you'd pass props through every component in between. useContext() skips all of that.
Step 1 — Create the context:
const AppContext = createContext();
Step 2 — Wrap your parent and put data on the value prop:
<AppContext.Provider value={text}>
<App />
</AppContext.Provider>

Step 3 — Grab it anywhere down the tree:
function Title() {
const text = useContext(AppContext);
return <h1>{text}</h1>;
}

No prop drilling. Component 7 just reaches up and grabs what it needs directly.


Portals — Rendering Outside Your Component Tree
Sometimes you need a component to visually break out of its parent — modals, dropdowns, tooltips. Portals let you render a component into any DOM element, not just its parent:
createPortal(

I am in the document body., document.body)
The component still lives in your React tree logically — events bubble normally — but it physically renders wherever you point it.

Suspense — Waiting for Things to Load
Suspense lets you define a fallback UI while something is loading:
<Suspense fallback={<p>Loading...</p>}>
<SlowComponent />
</Suspense>

Pairs really cleanly with lazy() for loading components only when they're actually needed:
const Component = lazy(() => import('./Component'));
<Suspense fallback={<p>Loading...</p>}>
<Component />
</Suspense>

The component's JavaScript doesn't even download until it's needed. Great for performance on larger apps.


**this** Keyword — It's About Who Called It, Not Where It Lives
This is one of those JavaScript concepts that confuses everyone until it's explained the right way. The rule is simple: this looks for whoever called it.
In a browser function, this points to the window object. In Node.js, it points to the global object.
Inside an object method, this refers to that object — because the object is the one calling it.
Here's where it gets interesting:
const user = {
name: "Deep",
logName: function() { console.log(this.name); }
};

user.logName(); ✅ — outputs "Deep" because user is calling it. this obeys user.
const standAlone = user.logName;
standAlone(); ❌ — outputs undefined because now a plain variable is calling it, not an object. this has no object to obey so it climbs up to window — and window.name is empty.
Same function. Different caller. Completely different result. this doesn't care where the function was defined — it only cares about who invoked it. Once that mental model locks in, this stops being scary.

Top comments (0)