Insights into Company
← React

Frontend Architecture

Understand the idea. Compare it. Explain it. Test yourself.

Question 1 of 5

How should a React project be structured?

Solution and explanation

Feature-based structure (recommended for medium and large apps)

src/
  app/                 # app shell: providers, router, global styles
    App.jsx
    routes.jsx
  features/
    jobs/
      api.js           # fetch functions / query hooks
      components/      # JobCard.jsx, JobFilters.jsx
      hooks/           # useJobs.js
      pages/           # JobsPage.jsx, JobDetailPage.jsx
      jobs.test.jsx
    auth/
    resume/
  components/          # shared UI: Button, Modal, Input, Table
  hooks/               # shared hooks: useDebounce, useLocalStorage
  lib/                 # api client (axios instance), formatters, constants
  assets/

Everything for one feature lives together, so a developer working on "jobs" rarely leaves that folder. Shared pieces are promoted to components/ or lib/ only when a second feature needs them.

Small projects

A flat components/, pages/, hooks/, services/ layout is fine; switch to feature folders when it grows.

Conventions that help teams

  • One component per file, PascalCase.jsx; hooks useCamelCase.js.
  • An index.js per feature exporting its public API only.
  • A single API client with base URL, auth header and error handling:
export const api = axios.create({ baseURL: import.meta.env.VITE_API_URL, withCredentials: true });
api.interceptors.response.use(r => r, err => {
  if (err.response?.status === 401) window.location.assign('/login');
  return Promise.reject(err);
});
  • Environment variables in .env (VITE_ prefix in Vite); never put secrets in frontend code.
  • Absolute imports (@/features/jobs) via path aliases.
  • ESLint + Prettier + TypeScript for consistency and type safety.

Separation of concerns

  • Pages: compose features and read route params.
  • Feature components: UI + calls to hooks.
  • Hooks: state and data logic.
  • lib/api: network and pure utilities.

Summary

Organise by feature, keep shared UI and utilities separate, centralise the API client, and enforce conventions with linting and TypeScript.

Practice explaining this
Question 2 of 5

How do error boundaries work?

Solution and explanation

What they are

An error boundary is a component that **catches JavaScript errors during rendering** of its children, logs them and shows a fallback UI instead of crashing the whole app (without one, React unmounts the entire tree and the user sees a blank page).

They are still written as **class components**, because they rely on lifecycle methods:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };                 // render the fallback next
  }

  componentDidCatch(error, info) {
    logToSentry(error, info.componentStack);   // report the error
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback ?? <p>Something went wrong. <button onClick={() => this.setState({ hasError: false })}>Try again</button></p>;
    }
    return this.props.children;
  }
}

<ErrorBoundary fallback={<p>Could not load the chart</p>}>
  <SalaryChart />
</ErrorBoundary>

The react-error-boundary package gives a ready-made function-friendly version with resetKeys and onReset.

What they catch and do not catch

CaughtNot caught
errors in rendererrors in event handlers (use try/catch)
errors in lifecycle methods and effects of childrenasync code such as setTimeout, promises
errors in constructors of childrenerrors in the boundary itself
server-side rendering errors

For async errors in handlers, catch them and put them in state, or rethrow during render so the boundary handles them.

Where to place them

  • One at the top level (whole-app fallback with a reload button).
  • Around each route, so one broken page does not break navigation.
  • Around risky widgets (third-party embeds, charts, rich text editors).
  • Around lazy components to handle failed chunk downloads after a deployment.

Summary

Error boundaries are class components using getDerivedStateFromError and componentDidCatch to catch render errors in their subtree and show a fallback; handle event and async errors separately.

Practice explaining this
Question 3 of 5

How do you secure API calls?

Solution and explanation

Ground rule

**Anything in the browser is public.** Users can read your JavaScript, change requests and call the API directly. Security must be enforced on the **server**; the frontend only avoids leaking data and makes attacks harder.

Authentication tokens

OptionXSS riskCSRF riskNotes
HttpOnly, Secure, SameSite cookietoken not readable by JSneeds SameSite or CSRF tokenrecommended (Laravel Sanctum SPA mode)
localStorage bearer tokenany injected script can steal itnonesimple but riskier
in-memory access token + HttpOnly refresh cookielowlowgood for JWT setups
// Cookie-based session (Laravel Sanctum)
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', { email, password }, { withCredentials: true });

Protect against XSS

  • React escapes output; avoid dangerouslySetInnerHTML, or sanitise with DOMPurify.
  • Never build URLs from user input without validation (javascript: links).
  • Set a **Content Security Policy** header.

CSRF

With cookies, use SameSite=Lax/Strict and the framework's CSRF token (the X-XSRF-TOKEN header that axios sends automatically).

CORS

Configure the API to allow only your frontend origin; CORS is a browser rule, not a security wall against direct calls.

Never put secrets in the frontend

Payment gateway secret keys, database URLs, third-party API secrets must stay on the server. VITE_/REACT_APP_ variables are compiled into the bundle and visible to everyone. Call such services through your own backend.

Server-side checks the frontend relies on

  • Authorise every request (can this user see application 42?), not only hide buttons.
  • Validate all input; rate-limit logins and OTPs; use HTTPS everywhere.

Handling expiry

An axios interceptor can refresh the token on 401 once, then redirect to login if it fails.

Summary

Use HttpOnly cookies or short-lived in-memory tokens, guard against XSS and CSRF, keep secrets on the server, and enforce authorisation on the API, because the client can never be trusted.

Practice explaining this
Question 4 of 5

What is hydration?

Solution and explanation

What it is

With server-side rendering (SSR), the server sends ready HTML so the page appears quickly and is crawlable by search engines. That HTML is not interactive yet. **Hydration** is the step where React loads in the browser, renders the same component tree, attaches event listeners to the existing HTML and takes over, without recreating the DOM.

// client entry
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);

(Compare with createRoot(...).render(<App/>) for client-only apps, which builds the DOM from scratch.)

Hydration mismatch

React expects the first client render to produce exactly the server's HTML. If not, it warns and may re-render the whole subtree. Common causes:

  • Date.now(), Math.random(), or current time in render.
  • Reading window, localStorage or screen size during render (undefined on the server).
  • Locale differences in number or date formatting.
  • Invalid HTML nesting (<div> inside <p>).

Fix: render browser-only values after mount:

const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
return <span>{mounted ? new Date().toLocaleTimeString() : ''}</span>;

Cost of hydration

The browser still downloads and runs all component JavaScript, so a page can look ready but not respond to clicks (poor INP). Modern improvements:

  • **Selective/streaming hydration (React 18):** parts wrapped in Suspense hydrate independently, and parts the user interacts with are prioritised.
  • **React Server Components (Next.js App Router):** server-only components send no JavaScript, so less to hydrate.
  • **Islands architecture (Astro):** only interactive widgets are hydrated.

Summary

Hydration attaches React's interactivity to server-rendered HTML; the client render must match the server's output, and less client JavaScript means faster hydration.

Practice explaining this
Question 5 of 5

CSR versus SSR versus SSG?

Solution and explanation

The three rendering strategies

CSR (client-side rendering)SSR (server-side rendering)SSG (static site generation)
HTML builtin the browseron the server per requestat build time
First paintslower (blank until JS loads)fastfastest (served from CDN)
SEOweakerstrongstrong
Data freshnesslivelive per requestas of the last build
Server costlow (static files)higher (render each request)lowest
Exampleadmin dashboard, logged-in appjob search results, product pages with live pricesblog, docs, marketing pages

CSR

Vite + React builds a bundle; the server sends an almost empty index.html, and JavaScript fetches data and renders. Great for apps behind login where SEO does not matter.

SSR

The server (Next.js, Remix) runs React for each request, sends complete HTML, then the browser hydrates it.

// Next.js App Router: a server component fetching per request
export default async function JobsPage({ searchParams }) {
  const jobs = await fetch(`${API}/jobs?city=${searchParams.city}`, { cache: 'no-store' }).then(r => r.json());
  return <JobList jobs={jobs} />;
}

SSG and ISR

Pages are generated once at build time and served as static files. **Incremental Static Regeneration (ISR)** regenerates a page in the background after a set time:

fetch(`${API}/companies/${slug}`, { next: { revalidate: 3600 } });   // refresh hourly

Good for company pages or articles that change occasionally but need SEO and speed.

Choosing

  • Public pages that must rank on Google (jobs, companies): SSR or SSG/ISR.
  • Content that rarely changes: SSG.
  • Private, highly interactive dashboards: CSR.
  • Real apps mix them: Next.js lets each route choose.

Summary

CSR renders in the browser, SSR on the server per request, SSG at build time; choose per page based on SEO needs, data freshness and server cost.

Practice explaining this