React कंपोनेंट्स, हुक्स और स्टेट मैनेजमेंट के साथ डायनामिक UI बनाएं – Detailed notes in English and हिंदी
document.getElementById(...).innerHTML = ...). State was scattered
across DOM attributes, global variables, and event handlers — nobody knew the "single source
of truth". As the app grew, the code became a tangle of event listeners and callbacks: slow
to render, hard to debug, and impossible to reuse. There was no reliable way to keep the
view automatically in sync with the data.UI = f(state).
// Old way (plain JavaScript)
let count = 0;
btn.onclick = () => { count++; btn.textContent = `Clicked ${count} times`; };
// React way
import { useState } from 'react';
function ClickCounter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
In React you only change the state. React re-renders the component automatically.
The view can never drift away from the data.
| Category | Options | Description |
|---|---|---|
| By component kind | Function components (modern) / Class components (legacy) | Function components with Hooks are the current standard. |
| By rendering strategy | CSR, SSR, SSG, ISR, React Server Components (RSC) | CSR renders in the browser; SSR/SSG render on the server for SEO and speed. |
| By platform | React DOM (web), React Native (mobile), React Three Fiber (3D) | Same mental model, different renderers. |
useState and
useEffect that add state and side effects to function components.
┌──────────────────┐
│ App (Root) │
└────────┬─────────┘
│
┌───────────────┴───────────────┐
│ │
┌────▼─────┐ ┌─────▼──────┐
│ Header │ │ Main │
└────┬─────┘ └─────┬──────┘
│ │
┌────▼─────┐ ┌──────────┴──────────┐
│ Logo │ ┌────▼────┐ ┌─────▼─────┐
└──────────┘ │ Counter │ │ TodoList │
└─────────┘ └───────────┘
State / Props change
│
▼
┌─────────────────────┐
│ New Virtual DOM │
│ (JS object tree) │
└──────────┬──────────┘
│ diff / reconcile
┌──────────▼──────────┐
│ Compare with old │
│ Virtual DOM │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Minimal real DOM │
│ updates only │
└─────────────────────┘
One-way data flow:
Parent ──── props (data down) ────► Child
Parent ◄─── callback (events up) ─── Child
npm create vite@latest my-app -- --template react and run the dev
server.
Greeting component that accepts a name prop and
renders “Hello, <name>!”.LikeButton component that shows “Likes: 0” and increments on
click.App with Header, Greeting, and two
independent LikeButtons.document.getElementById(...).innerHTML = ...)। State DOM attributes, global
variables और event handlers में बिखरी रहती थी — किसी को "single source of truth" का पता ही
नहीं चलता था। App बड़ा होने पर code event listeners और callbacks का जाल बन जाता था: render
धीमा, debug करना मुश्किल, और reuse करना असंभव। View को data के साथ अपने आप sync रखने का कोई
भरोसेमंद तरीका नहीं था।UI = f(state)।
// पुराना तरीका (plain JavaScript)
let count = 0;
btn.onclick = () => { count++; btn.textContent = `Clicked ${count} times`; };
// React तरीका
import { useState } from 'react';
function ClickCounter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
React में आप सिर्फ state बदलते हैं। React component को अपने आप दोबारा render करता
है। View और data कभी अलग नहीं हो सकते।
| श्रेणी | विकल्प | विवरण |
|---|---|---|
| Component के प्रकार से | Function components (आधुनिक) / Class components (पुराने) | Hooks वाले function components आज standard हैं। |
| Rendering strategy से | CSR, SSR, SSG, ISR, React Server Components (RSC) | CSR browser में render होता है; SSR/SSG server पर — SEO और speed के लिए। |
| Platform से | React DOM (web), React Native (mobile), React Three Fiber (3D) | वही सोच, अलग renderers। |
useState, useEffect जैसे functions।
┌──────────────────┐
│ App (Root) │
└────────┬─────────┘
│
┌───────────────┴───────────────┐
│ │
┌────▼─────┐ ┌─────▼──────┐
│ Header │ │ Main │
└────┬─────┘ └─────┬──────┘
│ │
┌────▼─────┐ ┌──────────┴──────────┐
│ Logo │ ┌────▼────┐ ┌─────▼─────┐
└──────────┘ │ Counter │ │ TodoList │
└─────────┘ └───────────┘
State / Props बदला
│
▼
┌─────────────────────┐
│ नया Virtual DOM │
└──────────┬──────────┘
│ diff / reconcile
┌──────────▼──────────┐
│ पुराने Virtual DOM │
│ से तुलना │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ सिर्फ ज़रूरी real │
│ DOM updates │
└─────────────────────┘
एक दिशा में data flow:
Parent ──── props (data नीचे) ────► Child
Parent ◄─── callback (event ऊपर) ─── Child
npm create vite@latest my-app -- --template react से नया React project
बनाइए।Greeting component लिखिए जो name prop लेता है।LikeButton बनाइए जो click पर count बढ़ाता है।App बनाइए जिसमें Header, Greeting और दो
अलग LikeButton हों।
// Simple component with a prop
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Component using children for composition
function Card({ title, children }) {
return (
<div className="card">
<h3>{title}</h3>
<div className="card-body">{children}</div>
</div>
);
}
// Using both
function App() {
return (
<div>
<Greeting name="Amit" />
<Greeting name="Priya" />
<Card title="Welcome">
<p>This is inside the Card.</p>
<button>Click me</button>
</Card>
</div>
);
}
| Type | Description | Example |
|---|---|---|
| Function components | Plain JS functions returning JSX. Modern standard. | function Card() { return <div />; } |
| Class components | ES6 classes extending React.Component. Legacy. | class Card extends React.Component |
| Container / Presentational | Container handles logic; presentational handles UI. | <UserContainer /> vs <UserView /> |
| Compound components | Parent + children share implicit state as one API. | <Tabs><Tabs.Tab /></Tabs> |
| HOC (Higher-Order Component) | Function that takes a component and returns a wrapped one. | withAuth(Dashboard) |
<>...</>).
Parent ──── props (data down) ────► Child
Parent ◄─── callback (events up) ─── Child
Component Tree:
<App>
├─ <Header title="My Site" />
├─ <Card title="Welcome">
│ ├─ <p>Hello World</p>
│ └─ <Button label="OK" onClick={handleOk} />
└─ <Footer year={2025} />
Composition:
<Card>
└─ children = whatever you put inside
</Card>
Card component that accepts title and
children.Button component with label and
onClick props.UserList that receives an array of users via props.
// Prop के साथ साधारण component
function Greeting({ name }) {
return <h1>नमस्ते, {name}!</h1>;
}
// Composition के लिए children वाला component
function Card({ title, children }) {
return (
<div className="card">
<h3>{title}</h3>
<div className="card-body">{children}</div>
</div>
);
}
// दोनों का उपयोग
function App() {
return (
<div>
<Greeting name="अमित" />
<Greeting name="प्रिया" />
<Card title="स्वागत">
<p>यह Card के अंदर है।</p>
<button>क्लिक कीजिए</button>
</Card>
</div>
);
}
| प्रकार | विवरण | उदाहरण |
|---|---|---|
| Function components | साधारण JS functions जो JSX return करते हैं। आधुनिक standard। | function Card() { return <div />; } |
| Class components | ES6 classes जो React.Component extend करती हैं। पुराने। | class Card extends React.Component |
| Container / Presentational | Container logic संभालता है; presentational UI। | <UserContainer /> बनाम <UserView /> |
| Compound components | Parent + children मिलकर एक API की तरह काम करते हैं। | <Tabs><Tabs.Tab /></Tabs> |
| HOC (Higher-Order Component) | Function जो component लेकर wrapped component देता है। | withAuth(Dashboard) |
<>...</>)।
Parent ──── props (data नीचे) ────► Child
Parent ◄─── callback (event ऊपर) ─── Child
Component Tree:
<App>
├─ <Header title="मेरी साइट" />
├─ <Card title="स्वागत">
│ ├─ <p>नमस्ते दुनिया</p>
│ └─ <Button label="ठीक" onClick={handleOk} />
└─ <Footer year={2025} />
Composition:
<Card>
└─ children = जो भी अंदर रखें
</Card>
Card component बनाइए जो title और
children लेता है।Button component बनाइए जिसमें label और
onClick props हों।UserList बनाइए जो props से users का array लेता है।useState hook, which returns a pair: the current value and a setter function.
State updates are asynchronous and must be immutable — you never modify the existing value;
you create a new one.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const [items, setItems] = useState([]);
const addItem = () => {
// Correct: create a NEW array
setItems(prev => [...prev, `Item ${prev.length + 1}`]);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
<button onClick={() => setCount(0)}>Reset</button>
<button onClick={addItem}>Add item</button>
<ul>
{items.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</div>
);
}
| Type | Description | Example |
|---|---|---|
| Local state | Owned by one component, e.g., form input value. | const [name, setName] = useState('') |
| Lifted state | Moved to a common parent so siblings can share it. | <Parent value={x} setValue={setX} /> |
| Derived state | Computed from props or other state — do not store if derivable. | const total = items.length |
| Global state | Shared across many components (Context, Redux, Zustand). | useStore() |
| Server state | Data from APIs with caching and syncing (TanStack Query). | useQuery(...) |
useState is easy to learn and use.useState calls can coexist
cleanly.setCount(c => c + 1).
setCount(count + 1)
│
▼
State updated
│
▼
Component re-renders
│
▼
New JSX → diff → DOM updated
Immutable update pattern:
// Wrong
items.push(newItem); // no re-render
setItems(items);
// Correct
setItems([...items, newItem]);
// or
setItems(prev => [...prev, newItem]);
Toggle component using state (on/off).Temperature component with Celsius/Fahrenheit conversion.count = count + 1 does not re-render.useState hook से बनती है, जो एक
pair return करता है: current value और setter function। State updates asynchronous होते हैं और
immutable होने चाहिए — मौजूदा value को modify नहीं करते, नई बनाते हैं।
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const [items, setItems] = useState([]);
const addItem = () => {
// सही: नया array बनाएँ
setItems(prev => [...prev, `Item ${prev.length + 1}`]);
};
return (
<div>
<p>गिनती: {count}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
<button onClick={() => setCount(0)}>रीसेट</button>
<button onClick={addItem}>Item जोड़ें</button>
<ul>
{items.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</div>
);
}
| प्रकार | विवरण | उदाहरण |
|---|---|---|
| Local state | एक component की अपनी, जैसे form input value। | const [name, setName] = useState('') |
| Lifted state | common parent पर ले जाना ताकि siblings share कर सकें। | <Parent value={x} setValue={setX} /> |
| Derived state | props या दूसरे state से निकाला गया — अगर derivable हो तो store न करें। | const total = items.length |
| Global state | कई components में shared (Context, Redux, Zustand)। | useStore() |
| Server state | APIs से data जिसमें caching और syncing हो (TanStack Query)। | useQuery(...) |
useState सीखने और use करने में आसान।useState कॉल्स साफ-सुथरे साथ रह सकते हैं।
setCount(c => c + 1)।
setCount(count + 1)
│
▼
State update हुआ
│
▼
Component re-render
│
▼
नया JSX → diff → DOM update
Immutable update pattern:
// गलत
items.push(newItem); // कोई re-render नहीं
setItems(items);
// सही
setItems([...items, newItem]);
// या
setItems(prev => [...prev, newItem]);
Toggle component बनाइए (on/off)।count = count + 1 से re-render क्यों नहीं होता।this binding and split related logic across
lifecycle methods. A better way was needed to add state, effects, and other React features
to function components.useState, useEffect,
useContext, useRef, useReducer,
useMemo, useCallback. React 18/19 adds
useTransition, useDeferredValue, useId,
use.
import { useState, useEffect, useRef } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
return () => clearInterval(intervalRef.current);
}, []);
return <p>Seconds: {seconds}</p>;
}
| Hook | Purpose | Example |
|---|---|---|
| useState | Local state in function components. | const [n, setN] = useState(0) |
| useEffect | Side effects (fetch, subscriptions, timers) after render. | useEffect(() => {}, []) |
| useContext | Read values from a React context. | const theme = useContext(ThemeContext) |
| useRef | Mutable value that does not trigger re-render. | const inputRef = useRef(null) |
| useReducer | Complex state logic with a reducer function. | const [s, dispatch] = useReducer(reducer, init) |
| useMemo | Memoize an expensive computed value. | const v = useMemo(() => calc(x), [x]) |
| useCallback | Memoize a function reference. | const fn = useCallback(() => {}, [dep]) |
| useTransition | Mark non-urgent state updates. | const [pending, start] = useTransition() |
| useDeferredValue | Defer a value for cheaper re-renders. | const d = useDeferredValue(query) |
| useId | Stable IDs for accessibility. | const id = useId() |
use.
function Component() {
const [a] = useState(0); // hook 1
const [b] = useState(1); // hook 2
useEffect(() => {}, []); // hook 3
// Order MUST remain the same every render
}
Custom Hook Example:
function useWindowWidth() {
const [w, setW] = useState(window.innerWidth);
useEffect(() => {
const handler = () => setW(window.innerWidth);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return w;
}
useWindowWidth.useLocalStorage.useReducer to build a shopping cart.this binding और lifecycle methods में बँटा logic भी
समस्याएँ पैदा करते थे। Function components में state, effects और दूसरे React features जोड़ने
का बेहतर तरीका चाहिए था।useState,
useEffect, useContext, useRef,
useReducer, useMemo, useCallback। React 18/19 में
useTransition, useDeferredValue, useId,
use भी।
import { useState, useEffect, useRef } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
return () => clearInterval(intervalRef.current);
}, []);
return <p>सेकंड: {seconds}</p>;
}
| Hook | उद्देश्य | उदाहरण |
|---|---|---|
| useState | Function components में local state। | const [n, setN] = useState(0) |
| useEffect | Render के बाद side effects (fetch, subscriptions, timers)। | useEffect(() => {}, []) |
| useContext | React context से values पढ़ना। | const theme = useContext(ThemeContext) |
| useRef | Mutable value जो re-render trigger नहीं करती। | const inputRef = useRef(null) |
| useReducer | Reducer function से complex state logic। | const [s, dispatch] = useReducer(reducer, init) |
| useMemo | महँगी computed value memoize करना। | const v = useMemo(() => calc(x), [x]) |
| useCallback | Function reference memoize करना। | const fn = useCallback(() => {}, [dep]) |
| useTransition | Non-urgent state updates mark करना। | const [pending, start] = useTransition() |
| useDeferredValue | Value को defer करके सस्ते re-renders। | const d = useDeferredValue(query) |
| useId | Accessibility के लिए stable IDs। | const id = useId() |
use से शुरू होता है।
function Component() {
const [a] = useState(0); // hook 1
const [b] = useState(1); // hook 2
useEffect(() => {}, []); // hook 3
// हर render पर क्रम वही रहना चाहिए
}
Custom Hook उदाहरण:
function useWindowWidth() {
const [w, setW] = useState(window.innerWidth);
useEffect(() => {
const handler = () => setW(window.innerWidth);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return w;
}
useWindowWidth लिखिए।useLocalStorage लिखिए।useReducer से shopping cart बनाइए।useEffect runs after render and can return a cleanup function that runs before
the next effect or on unmount. The dependency array controls when the effect re-runs.
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch('/api/users', { signal: controller.signal });
const data = await res.json();
setUsers(data);
} catch (err) {
if (err.name !== 'AbortError') setError(err);
}
}
load();
return () => controller.abort();
}, []);
| Dependency Array | Effect Runs | Use Case |
|---|---|---|
[] (empty) |
Once after mount, cleanup on unmount | Fetch initial data, subscriptions |
[dep] |
After mount + whenever dep changes | React to prop or state changes |
| No array | After every render | Rarely needed |
| With cleanup | Cleanup runs before next effect and on unmount | Timers, subscriptions, fetches |
useMemo for computing
instead.
Mount → Render → Paint → useEffect runs
│
▼
(dep changes)
│
▼
cleanup runs
│
▼
useEffect runs again
│
▼
Unmount → cleanup runs last
Race condition guard:
1. useEffect starts fetch A (dep = 1)
2. dep changes to 2 → cleanup aborts fetch A
3. useEffect starts fetch B (dep = 2)
4. Only B's result is applied
useEffect render के बाद चलता है और cleanup function return कर सकता है जो अगले
effect से पहले या unmount पर चलता है। Dependency array तय करता है कि effect कब दोबारा चले।
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch('/api/users', { signal: controller.signal });
const data = await res.json();
setUsers(data);
} catch (err) {
if (err.name !== 'AbortError') setError(err);
}
}
load();
return () => controller.abort();
}, []);
| Dependency Array | Effect कब चलता है | उपयोग |
|---|---|---|
[] (खाली) |
Mount के बाद एक बार, unmount पर cleanup | Initial data fetch, subscriptions |
[dep] |
Mount के बाद + जब dep बदले | Prop या state change पर react करना |
| कोई array नहीं | हर render के बाद | शायद ही कभी ज़रूरत |
| Cleanup के साथ | Cleanup अगले effect से पहले और unmount पर | Timers, subscriptions, fetches |
useMemo use
करें।
Mount → Render → Paint → useEffect चलता है
│
▼
(dep बदला)
│
▼
cleanup चलता है
│
▼
useEffect फिर चलता है
│
▼
Unmount → cleanup आखिर में चलता है
Race condition guard:
1. useEffect fetch A शुरू करता है (dep = 1)
2. dep 2 हुआ → cleanup fetch A abort करता है
3. useEffect fetch B शुरू करता है (dep = 2)
4. सिर्फ B का result apply होता है
<Tabs>
<Tabs.List>
<Tabs.Tab>One</Tabs.Tab>
<Tabs.Tab>Two</Tabs.Tab>
</Tabs.List>
<Tabs.Panels>
<Tabs.Panel>Content 1</Tabs.Panel>
<Tabs.Panel>Content 2</Tabs.Panel>
</Tabs.Panels>
</Tabs>
The parent manages the active tab via context; children read it. Users get a flexible,
declarative API.
| Pattern | Purpose | Example |
|---|---|---|
| Container / Presentational | Split logic from UI. | <UserContainer><UserView /></UserContainer> |
| HOC (Higher-Order Component) | Function that takes a component and returns an enhanced one. | withAuth(Dashboard) |
| Render Props | Share logic via a function prop. | <Mouse render={({x,y}) => ...} /> |
| Compound Components | Parent + children share implicit state. | <Tabs><Tabs.Tab /></Tabs> |
| Context Providers | Share data without prop drilling. | <ThemeProvider> |
| Portals | Render outside the parent DOM hierarchy. | ReactDOM.createPortal(<Modal />, document.body) |
| Error Boundaries | Catch errors in child tree and show fallback UI. | <ErrorBoundary><App /></ErrorBoundary> |
| Suspense + lazy | Lazy load components with a fallback. | <Suspense fallback={...}><Lazy /></Suspense> |
ReactDOM.createPortal: Still respect React
event bubbling.componentDidCatch / getDerivedStateFromError.
React.lazy and query libraries.
<App>
<ErrorBoundary>
<Main />
{ReactDOM.createPortal(<Modal />, document.body)}
</ErrorBoundary>
</App>
DOM Tree (portal attaches outside):
body
├── #root
│ └── App → ErrorBoundary → Main
└── div.portal-root
└── Modal
ErrorBoundary flow:
Child throws
│
▼
getDerivedStateFromError → set hasError=true
│
▼
Render fallback UI instead of crashed tree
ErrorBoundary class component.Modal using a React portal.Accordion component.
<Tabs>
<Tabs.List>
<Tabs.Tab>एक</Tabs.Tab>
<Tabs.Tab>दो</Tabs.Tab>
</Tabs.List>
<Tabs.Panels>
<Tabs.Panel>सामग्री 1</Tabs.Panel>
<Tabs.Panel>सामग्री 2</Tabs.Panel>
</Tabs.Panels>
</Tabs>
Parent active tab को context से manage करता है; children पढ़ते हैं। Users को flexible,
declarative API मिलती है।
| Pattern | उद्देश्य | उदाहरण |
|---|---|---|
| Container / Presentational | Logic को UI से अलग करना। | <UserContainer><UserView /></UserContainer> |
| HOC (Higher-Order Component) | Function जो component लेकर enhanced component देता है। | withAuth(Dashboard) |
| Render Props | Function prop से logic share करना। | <Mouse render={({x,y}) => ...} /> |
| Compound Components | Parent + children implicit state share करते हैं। | <Tabs><Tabs.Tab /></Tabs> |
| Context Providers | Prop drilling के बिना data share करना। | <ThemeProvider> |
| Portals | Parent DOM hierarchy के बाहर render करना। | ReactDOM.createPortal(<Modal />, document.body) |
| Error Boundaries | Child tree में errors पकड़कर fallback UI दिखाना। | <ErrorBoundary><App /></ErrorBoundary> |
| Suspense + lazy | Fallback के साथ components lazy load करना। | <Suspense fallback={...}><Lazy /></Suspense> |
ReactDOM.createPortal use करते हैं: React event
bubbling फिर भी respect करते हैं।componentDidCatch /
getDerivedStateFromError।
React.lazy और query libraries के साथ।
<App>
<ErrorBoundary>
<Main />
{ReactDOM.createPortal(<Modal />, document.body)}
</ErrorBoundary>
</App>
DOM Tree (portal बाहर attach होता है):
body
├── #root
│ └── App → ErrorBoundary → Main
└── div.portal-root
└── Modal
ErrorBoundary flow:
Child throws
│
▼
getDerivedStateFromError → hasError=true
│
▼
crashed tree की जगह fallback UI render करें
ErrorBoundary class component बनाइए।Modal बनाइए।Accordion component implement कीजिए।useState works for one component, but real apps
have data needed by many components far apart in the tree. Passing props through dozens of
intermediate components (prop drilling) is painful. Server data also has its own concerns:
caching, invalidation, background refetch. Mixing all of this into one solution causes
complexity and bugs.
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 })),
reset: () => set({ count: 0 }),
}));
function Counter() {
const { count, increment, reset } = useStore();
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
<button onClick={reset}>Reset</button>
</div>
);
}
| Type of State | Recommended Tools | When to Use |
|---|---|---|
| Local state | useState, useReducer |
Single component or small subtree. |
| Global UI state | Context + useReducer, Zustand, Jotai, Redux Toolkit | Theme, auth, modals, shared UI state. |
| Server state | TanStack Query, SWR, RTK Query, Apollo | Data fetched from APIs with caching and syncing. |
Data needed by one component? → useState Data needed by many components? → Context + useReducer / Zustand Data from an API? → TanStack Query / SWR Very large app, strict flow? → Redux Toolkit Layered view: ┌──────────────────────────────┐ │ Server state (TanStack Query)│ ├──────────────────────────────┤ │ Global UI state (Zustand) │ ├──────────────────────────────┤ │ Local state (useState) │ └──────────────────────────────┘
useState and TanStack Query. Reach for Redux Toolkit when you need strict
predictability and dev tools, Zustand when you want simplicity, and Context when the state
rarely changes. Keeping each category in its own layer makes apps easier to reason about and
test.
useState एक component के लिए ठीक है, लेकिन असली
apps में data कई दूर-दूर components को चाहिए। दर्जनों intermediate components से props भेजना
(prop drilling) painful है। Server data के अपने concerns हैं: caching, invalidation,
background refetch। सब कुछ एक solution में मिलाने से complexity और bugs बढ़ते हैं।
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 })),
reset: () => set({ count: 0 }),
}));
function Counter() {
const { count, increment, reset } = useStore();
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
<button onClick={reset}>रीसेट</button>
</div>
);
}
| State का प्रकार | Recommended Tools | कब Use करें |
|---|---|---|
| Local state | useState, useReducer |
एक component या छोटा subtree। |
| Global UI state | Context + useReducer, Zustand, Jotai, Redux Toolkit | Theme, auth, modals, shared UI state। |
| Server state | TanStack Query, SWR, RTK Query, Apollo | APIs से data जिसमें caching और syncing हो। |
Data एक component को चाहिए? → useState Data कई components को चाहिए? → Context + useReducer / Zustand Data API से आता है? → TanStack Query / SWR बहुत बड़ा app, strict flow? → Redux Toolkit Layered view: ┌──────────────────────────────┐ │ Server state (TanStack Query)│ ├──────────────────────────────┤ │ Global UI state (Zustand) │ ├──────────────────────────────┤ │ Local state (useState) │ └──────────────────────────────┘
useState और TanStack Query। जब strict predictability और dev tools चाहिए तो
Redux Toolkit, simplicity चाहिए तो Zustand, और rarely बदलने वाली state के लिए Context। हर
category को उसकी अपनी layer में रखने से apps समझने और test करने में आसान हो जाते हैं।
/users/42 and /dashboard, the back button, bookmarking,
and deep links. Without a router, you would need full page reloads or manual history
manipulation. SEO, analytics, and share links all depend on real URLs.
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UsersLayout />}>
<Route index element={<UsersList />} />
<Route path=":id" element={<UserDetail />} />
</Route>
<Route path="/dashboard" element={
<ProtectedRoute><Dashboard /></ProtectedRoute>
} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
| Concept | Description | Hook / API |
|---|---|---|
| Nested routes | Child routes rendered inside a parent layout. | <Outlet /> |
| Route params | Dynamic segments like :id. |
useParams() |
| Query strings | Read/write URL query parameters. | useSearchParams() |
| Programmatic navigation | Push/replace routes in code. | useNavigate() |
| Protected routes | Wrapper that redirects unauthenticated users. | <Navigate to="/login" /> |
| Lazy routes | Code split per route. | React.lazy + Suspense |
index.html for all routes.
React.lazy.
<BrowserRouter>
└─ <Routes>
├─ "/" → <Home />
├─ "/users" → <UsersLayout />
│ ├─ index → <UsersList />
│ └─ ":id" → <UserDetail />
├─ "/dashboard" → <ProtectedRoute> → <Dashboard />
└─ "*" → <NotFound />
ProtectedRoute example:
function ProtectedRoute({ children }) {
const authed = useAuth();
return authed ? children : <Navigate to="/login" replace />;
}
<Outlet />.ProtectedRoute that redirects to /login./users/42 और /dashboard जैसे URLs, back button, bookmarking और
deep links expect करते हैं। Router के बिना full page reloads या manual history manipulation
करनी पड़ेगी। SEO, analytics और share links सब असली URLs पर depend करते हैं।
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UsersLayout />}>
<Route index element={<UsersList />} />
<Route path=":id" element={<UserDetail />} />
</Route>
<Route path="/dashboard" element={
<ProtectedRoute><Dashboard /></ProtectedRoute>
} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
| Concept | विवरण | Hook / API |
|---|---|---|
| Nested routes | Child routes parent layout के अंदर render। | <Outlet /> |
| Route params | :id जैसे dynamic segments। |
useParams() |
| Query strings | URL query parameters read/write। | useSearchParams() |
| Programmatic navigation | Code में push/replace। | useNavigate() |
| Protected routes | Wrapper जो unauthenticated users को redirect करता है। | <Navigate to="/login" /> |
| Lazy routes | प्रति route code split। | React.lazy + Suspense |
index.html serve करना
पड़ता है।React.lazy से।
<BrowserRouter>
└─ <Routes>
├─ "/" → <Home />
├─ "/users" → <UsersLayout />
│ ├─ index → <UsersList />
│ └─ ":id" → <UserDetail />
├─ "/dashboard" → <ProtectedRoute> → <Dashboard />
└─ "*" → <NotFound />
ProtectedRoute उदाहरण:
function ProtectedRoute({ children }) {
const authed = useAuth();
return authed ? children : <Navigate to="/login" replace />;
}
<Outlet /> से shared layout वाला nested route बनाइए।ProtectedRoute implement कीजिए जो /login पर redirect करे।useState leads to verbose code, plus you need
validation, error messages, loading states, and file inputs. Doing this manually for every
form is repetitive and error-prone. Poor validation leads to bad UX and insecure backends.
value and onChange wired together. An uncontrolled component
keeps its value in the DOM and is read via refs. Libraries like React Hook Form (RHF) and
Formik reduce boilerplate and add validation. Server-side validation must always complement
client-side validation.
import { useForm } from 'react-hook-form';
function LoginForm() {
const {
register, handleSubmit,
formState: { errors, isSubmitting }
} = useForm();
const onSubmit = async (data) => {
await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(data),
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email is required',
pattern: { value: /\\S+@\\S+/, message: 'Invalid email' }
})}
/>
{errors.email && <span>{errors.email.message}</span>}
<input
type="password"
{...register('password', { required: true, minLength: 8 })}
/>
{errors.password && <span>Password too short</span>}
<button disabled={isSubmitting}>
{isSubmitting ? 'Logging in...' : 'Login'}
</button>
</form>
);
}
| Type | Description |
|---|---|
| Controlled | Value lives in React state; source of truth is React. |
| Uncontrolled | Value lives in DOM; read via refs. |
| React Hook Form | Uncontrolled-based library with minimal re-renders. |
| Formik | Controlled-based library, popular in older code. |
| Server Actions / useActionState | React 19 form submission with server functions. |
| Schema validation (Zod, Yup) | Type-safe validation rules shared between client and server. |
isSubmitting for UX feedback.
aria-invalid and
aria-describedby.
Controlled:
state ── value ──► input
▲ │
└──── onChange ◄────┘
Uncontrolled:
input (DOM holds value)
│
└── read via ref on submit
Form submission flow:
User fills form
│
▼
Client validation (instant feedback)
│
▼
POST to server
│
▼
Server validation (final gate)
│
▼
Success / error response
useState से संभालने पर code बहुत लंबा हो जाता है,
और validation, error messages, loading states, file inputs भी चाहिए। हर form के लिए manually
यह करना repetitive और error-prone है। खराब validation से UX खराब और backend असुरक्षित होता
है।value और onChange जुड़े होते हैं। Uncontrolled component value DOM
में रखता है और refs से पढ़ी जाती है। React Hook Form (RHF) और Formik जैसी libraries
boilerplate कम करती हैं और validation जोड़ती हैं। Server-side validation हमेशा client-side
validation के साथ होनी चाहिए।
import { useForm } from 'react-hook-form';
function LoginForm() {
const {
register, handleSubmit,
formState: { errors, isSubmitting }
} = useForm();
const onSubmit = async (data) => {
await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(data),
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email ज़रूरी है',
pattern: { value: /\\S+@\\S+/, message: 'गलत email' }
})}
/>
{errors.email && <span>{errors.email.message}</span>}
<input
type="password"
{...register('password', { required: true, minLength: 8 })}
/>
{errors.password && <span>पासवर्ड छोटा है</span>}
<button disabled={isSubmitting}>
{isSubmitting ? 'लॉगिन हो रहा है...' : 'लॉगिन'}
</button>
</form>
);
}
| प्रकार | विवरण |
|---|---|
| Controlled | Value React state में; source of truth React। |
| Uncontrolled | Value DOM में; refs से पढ़ें। |
| React Hook Form | Uncontrolled-based library, कम re-renders। |
| Formik | Controlled-based library, पुराने code में popular। |
| Server Actions / useActionState | React 19 में server functions से form submission। |
| Schema validation (Zod, Yup) | Type-safe validation rules जो client और server में share होती हैं। |
isSubmitting से UX feedback।
aria-invalid और
aria-describedby use करें।
Controlled:
state ── value ──► input
▲ │
└──── onChange ◄────┘
Uncontrolled:
input (DOM value रखता है)
│
└── submit पर ref से पढ़ें
Form submission flow:
User form भरता है
│
▼
Client validation (तुरंत feedback)
│
▼
Server को POST
│
▼
Server validation (final gate)
│
▼
Success / error response
fetch inside useEffect means you must manually handle loading
states, errors, caching, refetching, deduplication, and race conditions. This is a lot of
repetitive, error-prone code. Server state is fundamentally different from UI state and
deserves its own tools.
import { useQuery, useMutation, useQueryClient }
from '@tanstack/react-query';
function Users() {
const qc = useQueryClient();
const { data, isLoading, error, refetch } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
});
const createUser = useMutation({
mutationFn: (user) => fetch('/api/users', {
method: 'POST', body: JSON.stringify(user),
}),
onSuccess: () => qc.invalidateQueries({ queryKey: ['users'] }),
});
if (isLoading) return <Spinner />;
if (error) return <ErrorMsg error={error} onRetry={refetch} />;
return (
<>
<UserList users={data} />
<button onClick={() => createUser.mutate({ name: 'New' })}>
Add User
</button>
</>
);
}
| Tool | Type | Best For |
|---|---|---|
| fetch | Browser API | Simple one-off requests |
| Axios | HTTP client | Interceptors, request configs, timeouts |
| TanStack Query | Server-state library | Caching, mutations, infinite scroll, pagination |
| SWR | Server-state library | Lightweight alternative, stale-while-revalidate |
| RTK Query | Redux Toolkit add-on | Apps already using Redux |
| Apollo / urql | GraphQL clients | GraphQL APIs |
useInfiniteQuery).['users'],
['user', id].
Component mounts
│
▼
useQuery(key, fn)
│
▼
Cache hit? ── yes → return cached + refetch in background
│
no
▼
Fetch → loading → success/error
│
▼
Cache stored under key
│
▼
Mutations invalidate → refetch
Optimistic update flow:
User clicks "Add"
│
▼
UI shows new item immediately
│
▼
Server request in background
│
▼
On success → keep / refetch
On error → rollback
fetch/Axios for simple cases and as the low-level engine inside your query
functions. This separation — server state in a query library, UI state in React — makes apps
dramatically simpler, faster, and more predictable. Design query keys carefully, and use
optimistic updates for a snappy feel.fetch and useState/useEffect.useInfiniteQuery.useEffect के अंदर raw fetch से करने पर loading states, errors,
caching, refetching, deduplication और race conditions manually संभालने पड़ते हैं। यह बहुत
repetitive, error-prone code है। Server state असल में UI state से fundamentally अलग है और उसके
अपने tools चाहिए।
import { useQuery, useMutation, useQueryClient }
from '@tanstack/react-query';
function Users() {
const qc = useQueryClient();
const { data, isLoading, error, refetch } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
});
const createUser = useMutation({
mutationFn: (user) => fetch('/api/users', {
method: 'POST', body: JSON.stringify(user),
}),
onSuccess: () => qc.invalidateQueries({ queryKey: ['users'] }),
});
if (isLoading) return <Spinner />;
if (error) return <ErrorMsg error={error} onRetry={refetch} />;
return (
<>
<UserList users={data} />
<button onClick={() => createUser.mutate({ name: 'नया' })}>
User जोड़ें
</button>
</>
);
}
| Tool | प्रकार | सबसे अच्छा |
|---|---|---|
| fetch | Browser API | Simple one-off requests |
| Axios | HTTP client | Interceptors, request configs, timeouts |
| TanStack Query | Server-state library | Caching, mutations, infinite scroll, pagination |
| SWR | Server-state library | हल्का विकल्प, stale-while-revalidate |
| RTK Query | Redux Toolkit add-on | जो apps पहले से Redux use करते हैं |
| Apollo / urql | GraphQL clients | GraphQL APIs |
useInfiniteQuery)।['users'],
['user', id]।
Component mount
│
▼
useQuery(key, fn)
│
▼
Cache hit? ── हाँ → cached + background refetch
│
नहीं
▼
Fetch → loading → success/error
│
▼
Cache key के नीचे stored
│
▼
Mutations invalidate → refetch
Optimistic update flow:
User "Add" क्लिक करता है
│
▼
UI नया item तुरंत दिखाता है
│
▼
Background में server request
│
▼
Success → रखें / refetch
Error → rollback
fetch/Axios simple cases और query functions के low-level engine के रूप में रखें।
यह separation — server state query library में, UI state React में — apps को dramatically
simpler, तेज़ और predictable बनाता है। Query keys सावधानी से design करें, और snappy feel के
लिए optimistic updates use करें।fetch और useState/useEffect से list fetch कीजिए।useInfiniteQuery से infinite scroll implement कीजिए।
import { motion, AnimatePresence } from 'framer-motion';
function Modal({ isOpen, onClose, children }) {
return (
<AnimatePresence>
{isOpen && (
<motion.div
className="overlay"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
role="dialog"
aria-modal="true"
>
<motion.div
className="modal"
initial={{ y: 40, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 40, opacity: 0 }}
onClick={e => e.stopPropagation()}
>
{children}
</motion.div>
</motion.div>
)}
</AnimatePresence>
);
}
| Category | Examples |
|---|---|
| Conditional rendering | &&, ternary, early return |
| Animations | Framer Motion, React Spring, CSS transitions |
| Overlays | Modals, tooltips, dropdowns, popovers (Radix, Headless UI) |
| Virtualized lists | react-window, react-virtualized, TanStack Virtual |
| Drag-and-drop | dnd-kit, react-beautiful-dnd |
| Accessibility | ARIA roles, focus trap, keyboard navigation |
| Charts | Recharts, visx, Chart.js with React |
Open modal │ ▼ Save current focus │ ▼ Focus first focusable element in modal │ ▼ Tab / Shift+Tab cycles inside modal │ ▼ Escape / click overlay → close │ ▼ Restore previous focus Virtualized list rendering: Full list (10,000 items): [1] [2] [3] ... [10000] Virtualized (visible window only): [9998] [9999] [10000] ← rendered rest is placeholder space
prefers-reduced-motion in your animations.
import { motion, AnimatePresence } from 'framer-motion';
function Modal({ isOpen, onClose, children }) {
return (
<AnimatePresence>
{isOpen && (
<motion.div
className="overlay"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
role="dialog"
aria-modal="true"
>
<motion.div
className="modal"
initial={{ y: 40, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 40, opacity: 0 }}
onClick={e => e.stopPropagation()}
>
{children}
</motion.div>
</motion.div>
)}
</AnimatePresence>
);
}
| श्रेणी | उदाहरण |
|---|---|
| Conditional rendering | &&, ternary, early return |
| Animations | Framer Motion, React Spring, CSS transitions |
| Overlays | Modals, tooltips, dropdowns, popovers (Radix, Headless UI) |
| Virtualized lists | react-window, react-virtualized, TanStack Virtual |
| Drag-and-drop | dnd-kit, react-beautiful-dnd |
| Accessibility | ARIA roles, focus trap, keyboard navigation |
| Charts | Recharts, visx, Chart.js with React |
Modal खोलें │ ▼ Current focus save करें │ ▼ Modal के पहले focusable element पर focus │ ▼ Tab / Shift+Tab modal के अंदर cycle करें │ ▼ Escape / overlay click → बंद │ ▼ पिछला focus restore करें Virtualized list rendering: Full list (10,000 items): [1] [2] [3] ... [10000] Virtualized (सिर्फ visible window): [9998] [9999] [10000] ← rendered बाकी placeholder space
prefers-reduced-motion respect कीजिए।React.memo, useMemo, useCallback,
React.lazy + Suspense, virtualisation, and the React DevTools Profiler.
const MemoChild = React.memo(function Child({ value, onClick }) {
return <button onClick={onClick}>{value}</button>;
});
function Parent({ data, id }) {
const handleClick = useCallback(() => doSomething(id), [id]);
const result = useMemo(() => expensiveCalc(data), [data]);
return <MemoChild value={result} onClick={handleClick} />;
}
| Technique | Purpose | When to Use |
|---|---|---|
React.memo |
Skip re-render if props are unchanged. | Child re-renders with same props. |
useMemo |
Cache an expensive computed value. | Heavy computation in render. |
useCallback |
Cache a function reference. | Memoized child needs stable callback. |
| Code splitting | React.lazy + Suspense or dynamic import. |
Large route components. |
| Virtualisation | Render only visible rows in long lists. | Lists over a few hundred items. |
| Concurrent features | useTransition, useDeferredValue. |
Slow, non-urgent updates. |
| Profiler | React DevTools Profiler. | Before optimising anything. |
Profile app → identify slow component
│
▼
Is it re-rendering too often? ── yes → React.memo / useCallback
│
no
▼
Is a computation heavy? ──────── yes → useMemo
│
no
▼
Is the bundle too large? ─────── yes → React.lazy + code splitting
│
no
▼
Is the list huge? ────────────── yes → virtualization
│
no
▼
Re-profile and verify improvement
React.memo to a row component and measure the improvement.React.lazy.useTransition for a slow search filter.React.memo,
useMemo, useCallback, React.lazy + Suspense,
virtualisation, और React DevTools Profiler।
const MemoChild = React.memo(function Child({ value, onClick }) {
return <button onClick={onClick}>{value}</button>;
});
function Parent({ data, id }) {
const handleClick = useCallback(() => doSomething(id), [id]);
const result = useMemo(() => expensiveCalc(data), [data]);
return <MemoChild value={result} onClick={handleClick} />;
}
| तकनीक | उद्देश्य | कब Use करें |
|---|---|---|
React.memo |
Props unchanged होने पर re-render skip करें। | Child same props से re-render। |
useMemo |
महँगी computed value cache करें। | Render में heavy computation। |
useCallback |
Function reference cache करें। | Memoized child को stable callback चाहिए। |
| Code splitting | React.lazy + Suspense या dynamic import। |
बड़े route components। |
| Virtualisation | लंबी lists में सिर्फ visible rows render करें। | कुछ सौ से ज़्यादा items वाली lists। |
| Concurrent features | useTransition, useDeferredValue। |
Slow, non-urgent updates। |
| Profiler | React DevTools Profiler। | Optimize करने से पहले। |
App profile करें → slow component पहचानें
│
▼
बहुत ज़्यादा re-render? ── हाँ → React.memo / useCallback
│
नहीं
▼
Computation महँगी? ──────── हाँ → useMemo
│
नहीं
▼
Bundle बड़ा? ───────────── हाँ → React.lazy + code splitting
│
नहीं
▼
List बहुत बड़ी? ────────── हाँ → virtualization
│
नहीं
▼
फिर profile करें और सुधार verify करें
React.memo जोड़कर सुधार measure कीजिए।React.lazy से route-level code splitting जोड़िए।useTransition use कीजिए।
import { render, screen, fireEvent } from '@testing-library/react';
import LikeButton from './LikeButton';
test('increments count on click', () => {
render(<LikeButton />);
expect(screen.getByText(/Likes: 0/)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button'));
expect(screen.getByText(/Likes: 1/)).toBeInTheDocument();
});
test('renders custom initial label', () => {
render(<LikeButton label="Hearts" />);
expect(screen.getByText(/Hearts: 0/)).toBeInTheDocument();
});
| Type | Scope | Tools |
|---|---|---|
| Unit | Single function, hook, or component in isolation. | Jest, Vitest |
| Component / Integration | Several components with user interactions. | React Testing Library |
| API mocking | Simulate network responses. | MSW, jest.mock |
| End-to-end | Real browser, real user flows. | Cypress, Playwright |
| Visual regression | Screenshot comparisons. | Percy, Chromatic |
▲ Few E2E tests (Cypress/Playwright)
╱ ╲
╱ ╲ Some integration tests (RTL)
╱─────╲
╱ ╲ Many unit tests (Jest/Vitest)
╱─────────╲
MSW flow:
Component → fetch('/api/users')
│
▼
MSW intercepts
│
▼
Returns mock JSON
│
▼
Component renders data
renderHook.
import { render, screen, fireEvent } from '@testing-library/react';
import LikeButton from './LikeButton';
test('click पर count बढ़ता है', () => {
render(<LikeButton />);
expect(screen.getByText(/Likes: 0/)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button'));
expect(screen.getByText(/Likes: 1/)).toBeInTheDocument();
});
test('custom initial label render करता है', () => {
render(<LikeButton label="Hearts" />);
expect(screen.getByText(/Hearts: 0/)).toBeInTheDocument();
});
| प्रकार | दायरा | Tools |
|---|---|---|
| Unit | एक function, hook, या component अलग से। | Jest, Vitest |
| Component / Integration | कई components user interactions के साथ। | React Testing Library |
| API mocking | Network responses simulate करना। | MSW, jest.mock |
| End-to-end | असली browser, असली user flows। | Cypress, Playwright |
| Visual regression | Screenshot तुलना। | Percy, Chromatic |
▲ कम E2E tests (Cypress/Playwright)
╱ ╲
╱ ╲ कुछ integration tests (RTL)
╱─────╲
╱ ╲ कई unit tests (Jest/Vitest)
╱─────────╲
MSW flow:
Component → fetch('/api/users')
│
▼
MSW intercept करता है
│
▼
Mock JSON return
│
▼
Component data render करता है
renderHook से custom hook के लिए Jest test जोड़िए।useTransition, and
useDeferredValue.
// app/users/page.tsx (Server Component by default)
async function UserList() {
const users = await db.user.findMany(); // runs on server
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
export default UserList;
No JavaScript for this component is shipped to the browser — it runs entirely on the
server.
| Technique | Description | Best For |
|---|---|---|
| SSR | Render HTML per request on the server, then hydrate. | Personalised, fresh content. |
| SSG | Pre-render HTML at build time. | Content that rarely changes. |
| ISR | Static pages regenerated in the background. | Large content sites, e-commerce. |
| React Server Components (RSC) | Components that run only on the server, no client JS. | Data-heavy pages, reduced bundle. |
| Hydration | Attach React to server-rendered HTML on the client. | Making SSR pages interactive. |
| TypeScript | Static types for props, state, and hooks. | Large teams, big codebases. |
| Concurrent features | useTransition, useDeferredValue, Suspense. |
Keeping UI responsive during slow updates. |
Browser request
│
▼
Server renders HTML + data
│
▼
HTML sent to browser (visible fast)
│
▼
JS bundle downloaded
│
▼
React hydrates HTML → interactive
│
▼
Subsequent navigation is client-side
RSC boundary:
Server Component (no JS shipped)
│
▼
Client Component (interactive)
│
▼
Server Component inside (again no JS)
useTransition for a slow search filter.useTransition, और
useDeferredValue शामिल हैं।
// app/users/page.tsx (डिफ़ॉल्ट रूप से Server Component)
async function UserList() {
const users = await db.user.findMany(); // server पर चलता है
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
export default UserList;
इस component का कोई JavaScript browser को नहीं भेजा जाता — यह पूरी तरह server पर चलता है।
| तकनीक | विवरण | सबसे अच्छा |
|---|---|---|
| SSR | प्रति request server पर HTML render, फिर hydrate। | Personalised, fresh content। |
| SSG | Build time पर HTML pre-render। | Content जो कम बदलता है। |
| ISR | Static pages background में regenerate। | बड़े content sites, e-commerce। |
| React Server Components (RSC) | सिर्फ server पर चलने वाले components, कोई client JS नहीं। | Data-heavy pages, कम bundle। |
| Hydration | Server-rendered HTML पर client में React attach करना। | SSR pages को interactive बनाना। |
| TypeScript | Props, state और hooks के लिए static types। | बड़ी teams, बड़े codebases। |
| Concurrent features | useTransition, useDeferredValue, Suspense। |
Slow updates के दौरान UI responsive रखना। |
Browser request
│
▼
Server HTML + data render करता है
│
▼
HTML browser को भेजा (जल्दी दिखता है)
│
▼
JS bundle download
│
▼
React HTML hydrate करता है → interactive
│
▼
आगे की navigation client-side
RSC boundary:
Server Component (कोई JS नहीं)
│
▼
Client Component (interactive)
│
▼
Server Component अंदर (फिर कोई JS नहीं)
useTransition use कीजिए।src/ ├── features/ │ ├── auth/ │ │ ├── components/ │ │ │ ├── LoginForm.tsx │ │ │ └── SignupForm.tsx │ │ ├── hooks/ │ │ │ └── useAuth.ts │ │ ├── api.ts │ │ └── index.ts │ └── todos/ │ ├── components/ │ ├── hooks/ │ └── api.ts ├── components/ # shared UI (Button, Modal) ├── hooks/ # shared hooks ├── lib/ # utilities ├── pages/ or app/ # routing entry points └── App.tsx
| Area | Best Practice | Why |
|---|---|---|
| Folder structure | Feature-based with shared folders at top level. | Predictable, scalable. |
| Composition | Composition over inheritance; props and children. | Flexible, testable. |
| Custom hooks | One concern per hook; prefix with use. |
Reusable logic. |
| Design system | Storybook + tokens + shared components. | Consistent UI. |
| Tooling | ESLint, Prettier, TypeScript, Husky pre-commit. | Fewer bugs, uniform style. |
| Environment | .env with VITE_/NEXT_PUBLIC_ prefixes.
|
Config without hardcoding. |
| Deployment | Vercel, Netlify, AWS, Docker + CI/CD. | Repeatable, safe releases. |
index.ts: Barrel exports.┌──────────────────────────────────┐ │ app/ (routing, providers) │ ├──────────────────────────────────┤ │ features/ (auth, todos, cart) │ ├──────────────────────────────────┤ │ components/ (Button, Modal) │ ├──────────────────────────────────┤ │ hooks/ lib/ (shared logic) │ ├──────────────────────────────────┤ │ services/ api/ (network) │ └──────────────────────────────────┘ Dependency rule: outer layers import from inner layers, not the reverse.
src/ ├── features/ │ ├── auth/ │ │ ├── components/ │ │ │ ├── LoginForm.tsx │ │ │ └── SignupForm.tsx │ │ ├── hooks/ │ │ │ └── useAuth.ts │ │ ├── api.ts │ │ └── index.ts │ └── todos/ │ ├── components/ │ ├── hooks/ │ └── api.ts ├── components/ # साझा UI (Button, Modal) ├── hooks/ # साझा hooks ├── lib/ # utilities ├── pages/ या app/ # routing entry points └── App.tsx
| क्षेत्र | Best Practice | क्यों |
|---|---|---|
| Folder structure | Feature-based, top level पर shared folders। | Predictable, scalable। |
| Composition | Inheritance की जगह composition; props और children। | Flexible, testable। |
| Custom hooks | एक hook एक concern; use से शुरू। |
Reusable logic। |
| Design system | Storybook + tokens + shared components। | Consistent UI। |
| Tooling | ESLint, Prettier, TypeScript, Husky pre-commit। | कम bugs, uniform style। |
| Environment | .env with VITE_/NEXT_PUBLIC_ prefixes।
|
Config बिना hardcode। |
| Deployment | Vercel, Netlify, AWS, Docker + CI/CD। | Repeatable, safe releases। |
index.ts से: Barrel exports।┌──────────────────────────────────┐ │ app/ (routing, providers) │ ├──────────────────────────────────┤ │ features/ (auth, todos, cart) │ ├──────────────────────────────────┤ │ components/ (Button, Modal) │ ├──────────────────────────────────┤ │ hooks/ lib/ (shared logic) │ ├──────────────────────────────────┤ │ services/ api/ (network) │ └──────────────────────────────────┘ Dependency rule: outer layers inner layers से import करें, उल्टा नहीं।
✔ Auth (login / signup) ✔ REST or GraphQL API ✔ Global state (Redux Toolkit / Zustand) ✔ Server state (TanStack Query) ✔ Routing + protected routes ✔ Forms with validation ✔ Responsive UI (Tailwind / CSS Modules) ✔ Accessibility (keyboard, ARIA) ✔ Tests (Jest + RTL, one Cypress flow) ✔ CI/CD + deployment (Vercel / Netlify) ✔ README with screenshots and live link
| Level | Example Projects | Focus Skills |
|---|---|---|
| Beginner | Todo app, Counter, Weather widget, Quiz app | Components, state, effects |
| Intermediate | Movie search, Blog, Expense tracker, Kanban board, Notes with auth | Routing, data fetching, forms |
| Advanced | E-commerce store, Chat app (WebSockets), Social feed, Admin dashboard, LMS | Global state, real-time, performance |
| Capstone | Full-stack app with auth, API, tests, CI/CD, and deployment | Everything combined |
Beginner ──► Todo / Weather / Quiz
│
▼
Intermediate ──► Movie search / Blog / Expense tracker
│
▼
Advanced ──► E-commerce / Chat / Admin dashboard
│
▼
Capstone ──► Full-stack + Auth + Tests + CI/CD + Deploy
Suggested timeline for a capstone:
Week 1: Setup + Auth + basic routing
Week 2: Core features + API integration
Week 3: Polish UI + tests + accessibility
Week 4: Deploy + README + demo video
✔ Auth (login / signup) ✔ REST या GraphQL API ✔ Global state (Redux Toolkit / Zustand) ✔ Server state (TanStack Query) ✔ Routing + protected routes ✔ Validation वाले forms ✔ Responsive UI (Tailwind / CSS Modules) ✔ Accessibility (keyboard, ARIA) ✔ Tests (Jest + RTL, एक Cypress flow) ✔ CI/CD + deployment (Vercel / Netlify) ✔ Screenshots और live link वाला README
| स्तर | उदाहरण Projects | Focus Skills |
|---|---|---|
| Beginner | Todo app, Counter, Weather widget, Quiz app | Components, state, effects |
| Intermediate | Movie search, Blog, Expense tracker, Kanban board, auth वाला Notes | Routing, data fetching, forms |
| Advanced | E-commerce store, Chat app (WebSockets), Social feed, Admin dashboard, LMS | Global state, real-time, performance |
| Capstone | auth, API, tests, CI/CD और deployment वाला full-stack app | सब कुछ combined |
Beginner ──► Todo / Weather / Quiz
│
▼
Intermediate ──► Movie search / Blog / Expense tracker
│
▼
Advanced ──► E-commerce / Chat / Admin dashboard
│
▼
Capstone ──► Full-stack + Auth + Tests + CI/CD + Deploy
Capstone के लिए सुझाया timeline:
Week 1: Setup + Auth + basic routing
Week 2: Core features + API integration
Week 3: UI polish + tests + accessibility
Week 4: Deploy + README + demo video