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
maindeployable and gives every change a reviewed, reversible history.
git switch -c feat/comments
git add -p
git commit -m "Add comments to post page"
git push -u origin feat/commentsWatch 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.jsonlists dependencies and scripts;package-lock.jsonpins 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 ciin 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
useStategives 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.
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
useEffectruns 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
FormDataon 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/withpage.tsxandlayout.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.
<BrowserRouter>
<Routes>
<Route element={<AppLayout />}>
<Route index element={<Home />} />
<Route path="posts/:id" element={<PostPage />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
// inside PostPage
const { id } = useParams();Fetching API data in React
Also called TanStack Query, loading states
- What
- A Vite React app loads data from your API in the browser. A library such as TanStack Query handles caching, loading and error states, retries and refetching after a mutation.
- Why
- Hand written fetch effects miss race conditions, caching and invalidation. A data library turns each API call into a few lines.
const { data, isPending, error } = useQuery({
queryKey: ['posts', page],
queryFn: () =>
fetch(`/api/posts?page=${page}`).then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
}),
});Vite dev server and API proxy
Also called Vite, VITE_ variables, Vite proxy
- What
- Vite serves the React app in development with instant reloads and builds static files for production. Its
server.proxyoption forwards/apicalls to your backend on another port. - Why
- The proxy makes frontend and API look like one origin in development, avoiding CORS setup until you deploy them separately.
export default defineConfig({
plugins: [react()],
server: {
proxy: { '/api': 'http://localhost:8000' },
},
});Watch out
Putting secrets in VITE_ variables: they are bundled into public JavaScript.