Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
264 posts found
From React 18 to 19.3: Concurrent Rendering, Actions, use(), ref as Prop, Activity, useEffectEvent, ViewTransition and Fragment Refs
Frontend PART 16

From React 18 to 19.3: Concurrent Rendering, Actions, use(), ref as Prop, Activity, useEffectEvent, ViewTransition and Fragment Refs

React 18 laid the base for concurrent rendering (createRoot, batching, transitions), 19 brought Actions, use() and ref as a prop, 19.2 Activity and useEffectEvent, and 19.3 stable ViewTransition and Fragment refs. We add ViewTransition and a Fragment ref to Bookstore, apply React Router 8.5's deprecation, and upgrade a small React 18 project to 19.3 with the 18.3 warnings, the TypeScript codemod and manual fixes.

15 Nov 2026 12 min 4
A Brief Look at Next.js: Server Components, the App Router, Server Actions, Cache Components and When an SPA Is Enough
Frontend PART 15

A Brief Look at Next.js: Server Components, the App Router, Server Actions, Cache Components and When an SPA Is Enough

Next.js runs React on the server: Server Components await data directly and their code never reaches the browser, Cache Components let you choose what is cached with 'use cache' and cacheLife, and every Server Function is a public endpoint that needs validation and authorization. We serve Bookstore's book details as a Partial Prerender with Next.js 16.4, call a Server Function directly with curl, and discuss when an SPA is enough.

15 Nov 2026 13 min 4
Finishing the Bookstore SPA End to End: Feature Folders, Authentication, Environments and Deployment
Frontend PART 14

Finishing the Bookstore SPA End to End: Feature Folders, Authentication, Environments and Deployment

Getting a React SPA ready for production means guarding feature boundaries with a lint rule, knowing that VITE_ variables are written into the bundle at build time so secrets stay out of the browser, and handing the session to a BFF that uses an HttpOnly cookie instead of a token. We add a small ASP.NET Core and YARP BFF to Bookstore and show the sign-in flow, the SPA fallback, cache headers, an nginx config and bundle analysis with real output.

15 Nov 2026 15 min 5
Testing React: Vitest, React Testing Library and Mocking APIs with MSW
Frontend PART 13

Testing React: Vitest, React Testing Library and Mocking APIs with MSW

The practical way to test React is to run React Testing Library, which queries the UI as a user does, on Vitest, which reuses the Vite config, and to fake the API at the network level with MSW without touching the code. In Bookstore we test the pure applyChange function, useDebouncedValue and useCart with renderHook, BookCard with user-event, and the catalog and checkout screens through the real route tree in a memory router, with real failures for getBy vs findBy and leaking store state.

15 Nov 2026 20 min 4
Performance in React: Understanding Re-renders, memo, useMemo, useCallback, the React Compiler and the Profiler
Frontend PART 12

Performance in React: Understanding Re-renders, memo, useMemo, useCallback, the React Compiler and the Profiler

Reducing re-renders only helps when there is a measured cost, and often the real cost is the browser's DOM work rather than React. On Bookstore's 5,000-row stock page we measure memo and useCallback cutting row renders from 5,000 to 1, an inline callback undoing that, the React Compiler halving render time while the click stays at 400 ms, and virtualization bringing it down to 40 ms; plus the effect of useDeferredValue and Activity.

15 Nov 2026 15 min 5
Global State in React: The Limits of Context, Zustand and When to Use Redux Toolkit
Frontend PART 11

Global State in React: The Limits of Context, Zustand and When to Use Redux Toolkit

Most "global state" is really server, URL or form state; for the small client state that is truly global, Zustand's store with selectors fixes Context's render-every-reader problem, while Redux Toolkit comes in when you need an action log and rules for a large team. In Bookstore we move the recently viewed books and the cart id into a persisted store, and show reading without selectors causing 13 renders instead of 1 and a selector returning a new object looping forever in Zustand 5.

15 Nov 2026 12 min 4
Forms in React: Controlled Inputs, Form Actions, useActionState, useFormStatus and react-hook-form + zod
Frontend PART 10

Forms in React: Controlled Inputs, Form Actions, useActionState, useFormStatus and react-hook-form + zod

React 19's form actions (useActionState, useFormStatus, useOptimistic) are enough for small forms; for forms with line items and nested data, react-hook-form with a zod schema means less code and fewer renders. On the Bookstore order form we show the controlled version rendering on every key, an action resetting the form after a validation error, useOptimistic reverting by itself on failure, and Problem Details errors mapped to fields with focus moved to them.

15 Nov 2026 16 min 4
Routing with React Router 8: Routes, Nested Layouts, URL Params, Loaders/Actions and Lazy Routes
Frontend PART 09

Routing with React Router 8: Routes, Nested Layouts, URL Params, Loaders/Actions and Lazy Routes

In React Router 8's data mode, routes are passed to createBrowserRouter as objects; layout routes and Outlet give nested pages, loaders fetch data before entering a route, middleware acts as a guard, actions handle forms and lazy enables code splitting. We split Bookstore into URLs, move the search into the query string, and show state leaking to the next book without a key, a lazy chunk downloading before a middleware redirect, and why a static server needs an SPA fallback.

15 Nov 2026 16 min 4
Data Fetching in React: From fetch + Effects to TanStack Query, Suspense and use()
Frontend PART 08

Data Fetching in React: From fetch + Effects to TanStack Query, Suspense and use()

Fetching in an effect gives you no cache, deduplication, retries or invalidation; TanStack Query gathers them around the query key. We move the Bookstore catalog and the server-side cart to TanStack Query and measure a revisited search coming from the cache, an optimistic update rolled back on a 500, a 409 Problem Details shown to the user, Suspense's 300 ms reveal window, and a promise created during render sending 3,739 requests through use() in three seconds.

15 Nov 2026 20 min 4
useRef, Context and Custom Hooks: DOM Access, Context Instead of DI and the Rules of Hooks
Frontend PART 07

useRef, Context and Custom Hooks: DOM Access, Context Instead of DI and the Rules of Hooks

useRef is a box that does not trigger renders (a DOM node or a timer id), while Context carries a value deep into the tree without props and re-renders every component that reads it when it changes. We move the Bookstore cart, theme and user into Context, measure a version where a theme change renders 28 components instead of 2, and show an inline ref callback stealing focus, a conditional hook crashing the app and the search split into custom hooks.

15 Nov 2026 19 min 4
Using useEffect Correctly: Synchronization, Cleanup, Dependency Arrays and "You Might Not Need an Effect"
Frontend PART 06

Using useEffect Correctly: Synchronization, Cleanup, Dependency Arrays and "You Might Not Need an Effect"

useEffect is not a lifecycle hook but a tool for synchronizing a component with an external system: every setup has a cleanup, and the dependency array lists the reactive values the effect reads. We connect the Bookstore catalog to API search and show with real network records that debounce and AbortController send one request even under StrictMode, that a late response overwrites the list without cleanup, and that useEffectEvent avoids a needless request.

15 Nov 2026 13 min 4
Where Should State Live? Lifting State Up, Controlled Inputs, Derived State and useReducer
Frontend PART 05

Where Should State Live? Lifting State Up, Controlled Inputs, Derived State and useReducer

State should live in the closest common ancestor of the components that need it; computable values stay out of state, you store an identity instead of a copy, and state that must reset on a prop change gets a key. We lift Bookstore's cart into App, turn it into a type-safe reducer with useReducer and a discriminated union, and show with real output that a separately kept total goes wrong on remove and that a details panel without a key carries a note to another book.

15 Nov 2026 15 min 3
Blog Map