Full stack development: Next.js and PostgreSQL

Sefism.

Chapter 02

Git, npm and React

Version control and packages, then React: components, state, effects, forms and routing for the interface your backend serves.

Git branches and pull requests

Also called PR, merge, rebase, pull request

What
A branch is a cheap pointer to a line of commits. You work on a branch, push it and open a pull request, where CI runs and teammates review before merging into main.
Why
Keeps main deployable and gives every change a reviewed, reversible history.
Shell
git switch -c feat/comments
git add -p
git commit -m "Add comments to post page"
git push -u origin feat/comments

Watch out

Committing .env files or secrets; once pushed, rotate the secret, because deleting the file does not remove it from history.

npm, package.json and lockfiles

Also called semver, npm ci, npm, lockfile

What
package.json lists dependencies and scripts; package-lock.json pins exact versions of the whole tree. Versions follow semver (MAJOR.MINOR.PATCH), and ^ allows minor and patch updates.
Why
Commit the lockfile and use npm ci in CI and Docker so every environment installs the same code.

Watch out

Installing a package for one small helper without checking its size, maintenance and security history.

Components and props

Also called JSX

What
A React component is a function that returns JSX. Props are its read only inputs, passed down from the parent, including children.
Why
Components break a UI into testable pieces, and one way data flow makes it clear where each value comes from.

Watch out

Defining a component inside another component, which remounts it and loses its state on every render.

State and useState

Also called useState, React state

What
useState gives a component a value that survives re-renders and a setter that triggers one. State is replaced, never mutated, and anything derivable from it is calculated during render.
Why
State lives in the lowest component that needs it, lifted up only when siblings share it. Server data belongs in a data layer, not copied into state.
TSX
const [todos, setTodos] = useState<Todo[]>([]);

function toggle(id: string) {
  setTodos((prev) =>
    prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t))
  );
}

Watch out

Mutating an array in state with push, so React sees the same reference and does not re-render.

Effects and useEffect

Also called useEffect, dependency array

What
useEffect runs after render to synchronise with something outside React, such as a subscription, a timer or a browser API, and returns a cleanup function.
Why
Effects are an escape hatch. Event logic belongs in handlers and derived values in render; overusing effects is the most common React bug.

Watch out

Fetching in an effect with no cleanup, so a slow old response overwrites a newer one when inputs change quickly.

Forms and validation

Also called controlled inputs, zod

What
Inputs are controlled by state or read from FormData on submit. Validation runs in the browser for fast feedback and again on the server, often with one shared schema library such as Zod.
Why
Good forms show errors next to the field and keep what the user typed. Client validation is a convenience, never a security check.

Watch out

Trusting client side validation alone; anyone can send any request straight to your API.

Routing

Also called React Router, App Router

What
Mapping URLs to screens. Next.js uses folders in app/ with page.tsx and layout.tsx; a Vite React app uses React Router, declaring routes in code with nested layouts and URL params.
Why
Every screen with its own URL can be bookmarked, shared and reloaded, and layouts keep navigation shells in place.
TypeScript
// app/posts/[id]/page.tsx
type Props = { params: Promise<{ id: string }> };

export default async function PostPage({ params }: Props) {
  const { id } = await params;
  const post = await prisma.post.findUnique({ where: { id } });
  if (!post) notFound();
  return <PostView post={post} />;
}

Server and client components

Also called RSC, use client, server component, client component

What
App Router components run on the server by default: they can be async, query the database directly and ship no JavaScript. A file starting with 'use client' makes client components that can use state, effects and event handlers.
Why
Data loading stays on the server near the database, secrets never reach the browser and bundles stay small.

Watch out

Importing a module that reads secrets or the database into a client component; mark such modules with import 'server-only'.

02 · Git, npm and React2 / 8