30 āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”: āļ„āļđāđˆāļĄāļ·āļ­āđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ

āļĢāļ§āļĄ 30 āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āļ›āļĩ 2026 āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ•āļ­āļšāđ€āļŠāļīāļ‡āļĨāļķāļāđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āđ€āļžāļ·āđˆāļ­āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļ„āļ§āđ‰āļēāļ•āļģāđāļŦāļ™āđˆāļ‡āļ™āļąāļāļžāļąāļ’āļ™āļē React

āļ āļēāļžāļ›āļĢāļ°āļāļ­āļšāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React āļžāļĢāđ‰āļ­āļĄāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļĨāļ°āļŪāļļāļāļ—āļĩāđˆāđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āļāļąāļ™

āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļ—āļ„āļ™āļīāļ„ React āļˆāļ°āļ§āļąāļ”āļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāđƒāļ™āđāļ™āļ§āļ„āļīāļ”āļžāļ·āđ‰āļ™āļāļēāļ™ āļĢāļđāļ›āđāļšāļšāļ‚āļąāđ‰āļ™āļŠāļđāļ‡ āđāļĨāļ°āđāļ™āļ§āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩ āļ„āļđāđˆāļĄāļ·āļ­āļ™āļĩāđ‰āļĢāļ§āļšāļĢāļ§āļĄ 30 āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ” āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ•āļ­āļšāđ€āļŠāļīāļ‡āļĨāļķāļāđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļāļēāļĢāđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āđ€āļ›āđ‡āļ™āđ„āļ›āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

āļ„āļģāđāļ™āļ°āļ™āļģāđƒāļ™āļāļēāļĢāđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§

āļ„āļģāļ–āļēāļĄāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļ–āļđāļāļˆāļąāļ”āđ€āļĢāļĩāļĒāļ‡āļ•āļēāļĄāļĢāļ°āļ”āļąāļšāļ„āļ§āļēāļĄāļĒāļēāļ āļāļēāļĢāļāļķāļāļāļ™āļžāļ·āđ‰āļ™āļāļēāļ™āđƒāļŦāđ‰āđāļĄāđˆāļ™āļĒāļģāļāđˆāļ­āļ™āđ€āļ‚āđ‰āļēāļŠāļđāđˆāđāļ™āļ§āļ„āļīāļ”āļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļˆāļ°āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļāļēāļĢāđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āļĄāļĩāđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļ—āļĩāđˆāļŠāļąāļ”āđ€āļˆāļ™āļĒāļīāđˆāļ‡āļ‚āļķāđ‰āļ™

āļžāļ·āđ‰āļ™āļāļēāļ™āļ‚āļ­āļ‡ React

1. Virtual DOM āļ„āļ·āļ­āļ­āļ°āđ„āļĢāđāļĨāļ°āļ—āļģāđ„āļĄ React āļ–āļķāļ‡āđƒāļŠāđ‰

Virtual DOM āļ„āļ·āļ­āļāļēāļĢāđāļ—āļ™āļ„āđˆāļēāļ‚āļ­āļ‡ DOM āļˆāļĢāļīāļ‡āđƒāļ™āļĢāļđāļ›āđāļšāļš JavaScript āļ—āļĩāđˆāļĄāļĩāļ™āđ‰āļģāļŦāļ™āļąāļāđ€āļšāļē React āđƒāļŠāđ‰āļŠāļīāđˆāļ‡āļ™āļĩāđ‰āđ€āļžāļ·āđˆāļ­āļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ•āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āđƒāļŦāđ‰āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

āļāļĢāļ°āļšāļ§āļ™āļāļēāļĢāļ›āļĢāļ°āļāļ­āļšāļ”āđ‰āļ§āļĒāļŠāļēāļĄāļ‚āļąāđ‰āļ™āļ•āļ­āļ™ āđ„āļ”āđ‰āđāļāđˆ React āļŠāļĢāđ‰āļēāļ‡āļŠāļģāđ€āļ™āļēāđ€āļŠāļĄāļ·āļ­āļ™āļ‚āļ­āļ‡ DOM āļāđˆāļ­āļ™ āļˆāļēāļāļ™āļąāđ‰āļ™āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāļŠāļģāđ€āļ™āļēāļ”āļąāļ‡āļāļĨāđˆāļēāļ§āļāļąāļšāđ€āļ§āļ­āļĢāđŒāļŠāļąāļ™āļāđˆāļ­āļ™āļŦāļ™āđ‰āļēāđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡ (āļ­āļąāļĨāļāļ­āļĢāļīāļ—āļķāļĄ diffing) āđāļĨāļ°āļŠāļļāļ”āļ—āđ‰āļēāļĒāļ™āļģāđ€āļ‰āļžāļēāļ°āļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āđ„āļ›āđƒāļŠāđ‰āļāļąāļš DOM āļˆāļĢāļīāļ‡ (reconciliation)

jsx
// Simplified example of the concept
// When state changes, React doesn't recreate the entire DOM
function Counter() {
  const [count, setCount] = useState(0)

  // Only the span containing count will be updated in the real DOM
  // The rest of the component is untouched
  return (
    <div>
      <h1>Counter</h1>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}

āļ§āļīāļ˜āļĩāļāļēāļĢāļ™āļĩāđ‰āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļ—āļĩāđˆāļĄāļĩāļ•āđ‰āļ™āļ—āļļāļ™āļŠāļđāļ‡āļšāļ™ DOM āđāļĨāļ°āļ—āļģāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āļ­āļąāļ›āđ€āļ”āļ•āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§

2. āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļāļąāļšāđāļšāļšāļ„āļĨāļēāļŠāļ•āđˆāļēāļ‡āļāļąāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ„āļ·āļ­āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ JavaScript āļ—āļĩāđˆāļĢāļąāļš props āđāļĨāļ°āļ„āļ·āļ™āļ„āđˆāļēāđ€āļ›āđ‡āļ™ JSX āļ™āļąāļšāļ•āļąāđ‰āļ‡āđāļ•āđˆ React 16.8 āđ€āļ›āđ‡āļ™āļ•āđ‰āļ™āļĄāļē āļŪāļļāļāļ­āļ™āļļāļāļēāļ•āđƒāļŦāđ‰āđƒāļŠāđ‰ state āđāļĨāļ° lifecycle āđƒāļ™āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āđ„āļ”āđ‰

jsx
// Functional component (recommended)
// More concise, easier to test, supports hooks
function Welcome({ name }) {
  const [visits, setVisits] = useState(0)

  useEffect(() => {
    setVisits(v => v + 1)
  }, [])

  return <h1>Hello {name}, visit #{visits}</h1>
}

// Class component (legacy)
// More verbose, requires this binding
class WelcomeClass extends React.Component {
  state = { visits: 0 }

  componentDidMount() {
    this.setState(prev => ({ visits: prev.visits + 1 }))
  }

  render() {
    return <h1>Hello {this.props.name}, visit #{this.state.visits}</h1>
  }
}

āļ›āļąāļˆāļˆāļļāļšāļąāļ™āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ–āļ·āļ­āđ€āļ›āđ‡āļ™āļĄāļēāļ•āļĢāļāļēāļ™ āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļ„āļĨāļēāļŠāļĒāļąāļ‡āļ„āļ‡āļĢāļ­āļ‡āļĢāļąāļšāļ­āļĒāļđāđˆāđāļ•āđˆāđ„āļĄāđˆāđāļ™āļ°āļ™āļģāļŠāļģāļŦāļĢāļąāļšāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒāđƒāļŦāļĄāđˆ

3. JSX āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

JSX āļ„āļ·āļ­āļŠāđˆāļ§āļ™āļ‚āļĒāļēāļĒāđ„āļ§āļĒāļēāļāļĢāļ“āđŒāļ‚āļ­āļ‡ JavaScript āļ—āļĩāđˆāļ­āļ™āļļāļāļēāļ•āđƒāļŦāđ‰āđ€āļ‚āļĩāļĒāļ™āļĄāļēāļĢāđŒāļāļ­āļąāļ›āļ āļēāļĒāđƒāļ™āđ‚āļ„āđ‰āļ” JSX āđ„āļĄāđˆāđƒāļŠāđˆ HTML āđāļ•āđˆāđ€āļ›āđ‡āļ™ JavaScript āđƒāļ™āļĢāļđāļ›āđāļšāļšāļ—āļĩāđˆāļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāļāļ§āđˆāļē

jsx
// What we write (JSX)
const element = (
  <div className="container">
    <h1>Title</h1>
    <p>Paragraph</p>
  </div>
)

// What Babel compiles (pure JavaScript)
const element = React.createElement(
  'div',
  { className: 'container' },
  React.createElement('h1', null, 'Title'),
  React.createElement('p', null, 'Paragraph')
)

āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļˆāļēāļ HTML āđ„āļ”āđ‰āđāļāđˆ āļāļēāļĢāđƒāļŠāđ‰ className āđāļ—āļ™ class, htmlFor āđāļ—āļ™ for, āļāļēāļĢāđƒāļŠāđ‰ camelCase āļŠāļģāļŦāļĢāļąāļšāđāļ­āļ•āļ—āļĢāļīāļšāļīāļ§āļ•āđŒ (onClick, tabIndex) āđāļĨāļ°āļ•āđ‰āļ­āļ‡āļ›āļīāļ”āđāļ—āđ‡āļāļ—āļĩāđˆāļ›āļīāļ”āđƒāļ™āļ•āļąāļ§āđ€āļ­āļ‡āđ€āļŠāļĄāļ­

4. state āļāļąāļš props āļ•āđˆāļēāļ‡āļāļąāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

Props āļ„āļ·āļ­āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļŠāđˆāļ‡āļˆāļēāļāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļĄāđˆāđ„āļ›āļĒāļąāļ‡āļĨāļđāļ āđ€āļ›āđ‡āļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļ­āđˆāļēāļ™āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§ āļŠāđˆāļ§āļ™ state āļ„āļ·āļ­āļŠāļ–āļēāļ™āļ°āļ āļēāļĒāđƒāļ™āļ‚āļ­āļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļĩāđˆāļŠāļēāļĄāļēāļĢāļ–āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āļœāđˆāļēāļ™ setter āđ„āļ”āđ‰

UserCard.jsxjsx
// name and role are props (immutable)
function UserCard({ name, role }) {
  // isExpanded is state (mutable)
  const [isExpanded, setIsExpanded] = useState(false)

  return (
    <div className="card">
      <h2>{name}</h2>
      <p>{role}</p>

      {/* Modifying state triggers a re-render */}
      <button onClick={() => setIsExpanded(!isExpanded)}>
        {isExpanded ? 'Collapse' : 'Details'}
      </button>

      {isExpanded && <UserDetails name={name} />}
    </div>
  )
}

// Usage
<UserCard name="Alice" role="Developer" />

āļŦāļĨāļąāļāļāļēāļĢāļžāļ·āđ‰āļ™āļāļēāļ™āļ„āļ·āļ­ props āđ„āļŦāļĨāļˆāļēāļāļšāļ™āļĨāļ‡āļĨāđˆāļēāļ‡ (āļžāđˆāļ­āđāļĄāđˆāđ„āļ›āļĒāļąāļ‡āļĨāļđāļ) āļŠāđˆāļ§āļ™ state āđ€āļ›āđ‡āļ™āļ‚āļ­āļ‡āđāļ•āđˆāļĨāļ°āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ°

5. āļ—āļģāđ„āļĄ key āđƒāļ™āļĢāļēāļĒāļāļēāļĢāļˆāļķāļ‡āļŠāļģāļ„āļąāļ

Key āļŠāđˆāļ§āļĒāđƒāļŦāđ‰ React āļĢāļ°āļšāļļāđ„āļ”āđ‰āļ§āđˆāļēāļĄāļĩāļ­āļ‡āļ„āđŒāļ›āļĢāļ°āļāļ­āļšāđƒāļ”āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡ āđ€āļžāļīāđˆāļĄ āļŦāļĢāļ·āļ­āļ–āļđāļāļĨāļšāļ­āļ­āļāļˆāļēāļāļĢāļēāļĒāļāļēāļĢ āļŦāļēāļāđ„āļĄāđˆāļĄāļĩ key āļ—āļĩāđˆāđ„āļĄāđˆāļ‹āđ‰āļģāđāļĨāļ°āļ„āļ‡āļ—āļĩāđˆ React āļ­āļēāļˆāđāļŠāļ”āļ‡āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļ—āļĩāđˆāđ„āļĄāđˆāļ„āļēāļ”āļ„āļīāļ”

jsx
// ❌ Bad practice: index as key
// Problem: if order changes, React loses tracking
{items.map((item, index) => (
  <ListItem key={index} item={item} />
))}

// ✅ Good practice: unique and stable identifier
{items.map(item => (
  <ListItem key={item.id} item={item} />
))}

// Concrete example of the problem with indices
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React' },
    { id: 2, text: 'Create a project' }
  ])

  // When deleting the first element with key={index}
  // React will think element 0's content changed
  // instead of understanding an element was removed

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

React Hooks

6. āļ­āļ˜āļīāļšāļēāļĒ useState āđāļĨāļ°āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ

useState āđƒāļŠāđ‰āļˆāļąāļ”āļāļēāļĢ state āļ āļēāļĒāđƒāļ™āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™ setter āļĢāļąāļšāđ„āļ”āđ‰āļ—āļąāđ‰āļ‡āļ„āđˆāļēāđƒāļŦāļĄāđˆāļŦāļĢāļ·āļ­āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļŠāļģāļŦāļĢāļąāļšāļ­āļąāļ›āđ€āļ”āļ•

jsx
// Declaration with initial value
const [count, setCount] = useState(0)

// ❌ Pitfall: multiple updates in the same cycle
function increment() {
  setCount(count + 1) // count = 0, sets 1
  setCount(count + 1) // count = 0 still, sets 1
  setCount(count + 1) // count = 0 still, sets 1
  // Final result: 1 (not 3)
}

// ✅ Solution: use the update function
function incrementCorrect() {
  setCount(prev => prev + 1) // 0 → 1
  setCount(prev => prev + 1) // 1 → 2
  setCount(prev => prev + 1) // 2 → 3
  // Final result: 3
}

// ❌ Pitfall: object mutation
const [user, setUser] = useState({ name: 'Alice', age: 25 })
user.age = 26 // Direct mutation, no re-render

// ✅ Solution: create a new object
setUser({ ...user, age: 26 })
// or
setUser(prev => ({ ...prev, age: 26 }))

7. useEffect āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢāļāļąāļšāļ­āļēāļĢāđŒāđ€āļĢāļĒāđŒāļ‚āļ­āļ‡ dependency

useEffect āļ—āļģāļ‡āļēāļ™ side effect āļŦāļĨāļąāļ‡āļˆāļēāļāļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒ āļ­āļēāļĢāđŒāđ€āļĢāļĒāđŒāļ‚āļ­āļ‡ dependency āļ„āļ§āļšāļ„āļļāļĄāļ§āđˆāļēāđ€āļ­āļŸāđ€āļŸāļāļ•āđŒāļˆāļ°āļ–āļđāļāđ€āļĢāļĩāļĒāļāđ€āļĄāļ·āđˆāļ­āđƒāļ”

jsx
// Executed on every render (rare, usually avoid)
useEffect(() => {
  console.log('Render completed')
})

// Executed only on mount (equivalent to componentDidMount)
useEffect(() => {
  console.log('Component mounted')

  // Cleanup on unmount (equivalent to componentWillUnmount)
  return () => {
    console.log('Component unmounted')
  }
}, [])

// Executed when userId changes
useEffect(() => {
  async function fetchUser() {
    const response = await fetch(`/api/users/${userId}`)
    const data = await response.json()
    setUser(data)
  }

  fetchUser()
}, [userId])

// ❌ Missing dependency - subtle bug
useEffect(() => {
  const timer = setInterval(() => {
    setCount(count + 1) // count is "captured" at its initial value
  }, 1000)
  return () => clearInterval(timer)
}, []) // count is missing from dependencies

// ✅ Fix with update function
useEffect(() => {
  const timer = setInterval(() => {
    setCount(prev => prev + 1) // No need for count in deps
  }, 1000)
  return () => clearInterval(timer)
}, [])
āļāļŽāļ‚āļ­āļ‡ ESLint

āļ„āļ§āļĢāđ€āļ›āļīāļ”āđƒāļŠāđ‰āļ‡āļēāļ™ eslint-plugin-react-hooks āđ€āļŠāļĄāļ­āđ€āļžāļ·āđˆāļ­āļ•āļĢāļ§āļˆāļˆāļąāļš dependency āļ—āļĩāđˆāļ‚āļēāļ”āļŦāļēāļĒāđ„āļ› āļāļŽāļ™āļĩāđ‰āļŠāđˆāļ§āļĒāļ›āđ‰āļ­āļ‡āļāļąāļ™āļšāļąāđŠāļāļ—āļĩāđˆāļ§āļīāļ™āļīāļˆāļ‰āļąāļĒāđ„āļ”āđ‰āļĒāļēāļāļˆāļģāļ™āļ§āļ™āļĄāļēāļ

8. āđ€āļĄāļ·āđˆāļ­āđƒāļ”āļ„āļ§āļĢāđƒāļŠāđ‰ useMemo āđāļĨāļ° useCallback

āļŪāļļāļāļ—āļąāđ‰āļ‡āļŠāļ­āļ‡āļ™āļĩāđ‰āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļš memoization āđ€āļžāļ·āđˆāļ­āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļ„āļģāļ™āļ§āļ“āļ‹āđ‰āļģāļŦāļĢāļ·āļ­āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ„āđˆāļēāđƒāļŦāļĄāđˆāđ‚āļ”āļĒāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™ āļ„āļ§āļĢāļĢāļ°āļ§āļąāļ‡āđ„āļĄāđˆāđƒāļŠāđ‰āļĄāļēāļāđ€āļāļīāļ™āđ„āļ›

jsx
// useMemo: memoizes a computed value
function ProductList({ products, filter }) {
  // Recalculated only if products or filter change
  const filteredProducts = useMemo(() => {
    console.log('Filtering...')
    return products.filter(p => p.category === filter)
  }, [products, filter])

  return <ul>{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}

// useCallback: memoizes a function
function ParentComponent() {
  const [count, setCount] = useState(0)

  // Without useCallback, handleClick is recreated on every render
  // Causing unnecessary re-renders of ExpensiveChild
  const handleClick = useCallback((id) => {
    console.log('Clicked:', id)
  }, []) // Empty deps = stable function

  return (
    <>
      <span>{count}</span>
      <button onClick={() => setCount(c => c + 1)}>+</button>
      {/* React.memo on ExpensiveChild for this to be effective */}
      <ExpensiveChild onClick={handleClick} />
    </>
  )
}

// ❌ Over-optimization: not needed here
const SimpleComponent = () => {
  // This calculation is trivial, useMemo adds overhead
  const doubled = useMemo(() => 2 * 2, [])
  return <span>{doubled}</span>
}

āļ„āļ§āļĢāđƒāļŠāđ‰āļŪāļļāļāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļžāļšāļ›āļąāļāļŦāļēāļ”āđ‰āļēāļ™āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ—āļĩāđˆāļŠāļąāļ”āđ€āļˆāļ™ āļŦāļĢāļ·āļ­āđ€āļĄāļ·āđˆāļ­āļ•āđ‰āļ­āļ‡āļāļēāļĢāļĢāļąāļāļĐāļē reference āļ—āļĩāđˆāļŠāđˆāļ‡āđƒāļŦāđ‰āļāļąāļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļĩāđˆāļ–āļđāļ memoize āđ„āļ§āđ‰āđƒāļŦāđ‰āļ„āļ‡āļ—āļĩāđˆ

9. useRef āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢāđāļĨāļ°āđƒāļŠāđ‰āđƒāļ™āļāļĢāļ“āļĩāđƒāļ”āļšāđ‰āļēāļ‡

useRef āļŠāļĢāđ‰āļēāļ‡ reference āļ—āļĩāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ”āđ‰āđāļĨāļ°āļ„āļ‡āļ­āļĒāļđāđˆāļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒ āđ‚āļ”āļĒāđ„āļĄāđˆāļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđƒāļŦāļĄāđˆāđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āļ„āđˆāļē

jsx
// Case 1: Access a DOM element
function TextInput() {
  const inputRef = useRef(null)

  const focusInput = () => {
    inputRef.current.focus()
  }

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus</button>
    </>
  )
}

// Case 2: Store a mutable value without re-render
function Timer() {
  const [seconds, setSeconds] = useState(0)
  const intervalRef = useRef(null)

  const start = () => {
    // Store the interval ID to be able to stop it
    intervalRef.current = setInterval(() => {
      setSeconds(s => s + 1)
    }, 1000)
  }

  const stop = () => {
    clearInterval(intervalRef.current)
  }

  return (
    <div>
      <span>{seconds}s</span>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  )
}

// Case 3: Keep the previous value
function usePrevious(value) {
  const ref = useRef()

  useEffect(() => {
    ref.current = value
  }, [value])

  return ref.current
}

10. āļ­āļ˜āļīāļšāļēāļĒ useContext āđāļĨāļ°āđ€āļĄāļ·āđˆāļ­āđƒāļ”āļ„āļ§āļĢāđƒāļŠāđ‰

useContext āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āđ€āļ‚āđ‰āļēāļ–āļķāļ‡ context āļ‚āļ­āļ‡ React āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļŠāđˆāļ‡ props āļ—āļ­āļ”āļ•āđˆāļ­āļāļąāļ™āļŦāļĨāļēāļĒāļŠāļąāđ‰āļ™ āđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļšāļ‚āđ‰āļ­āļĄāļđāļĨāđāļšāļš global āđ€āļŠāđˆāļ™ āļ˜āļĩāļĄāļŦāļĢāļ·āļ­āļœāļđāđ‰āđƒāļŠāđ‰āļ—āļĩāđˆāļĨāđ‡āļ­āļāļ­āļīāļ™āļ­āļĒāļđāđˆ

1. Create the contextjsx
const ThemeContext = createContext({
  theme: 'light',
  toggleTheme: () => {}
})

// 2. Create the provider
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')

  const toggleTheme = useCallback(() => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light')
  }, [])

  // Memoize the value to avoid unnecessary re-renders
  const value = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme])

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  )
}

// 3. Use the context
function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext)

  return (
    <button
      onClick={toggleTheme}
      className={theme === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-800'}
    >
      {theme === 'dark' ? 'Light' : 'Dark'} mode
    </button>
  )
}

// 4. Wrap the application
function App() {
  return (
    <ThemeProvider>
      <Header />
      <Main />
      <Footer />
    </ThemeProvider>
  )
}

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React / Next.js āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļĢāļđāļ›āđāļšāļšāļ‚āļąāđ‰āļ™āļŠāļđāļ‡

11. Higher-Order Component (HOC) āļ„āļ·āļ­āļ­āļ°āđ„āļĢ

HOC āļ„āļ·āļ­āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ—āļĩāđˆāļĢāļąāļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđ€āļ‚āđ‰āļēāļĄāļēāđāļĨāļ°āļ„āļ·āļ™āļ„āđˆāļēāđ€āļ›āđ‡āļ™āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđƒāļŦāļĄāđˆāļ—āļĩāđˆāļ–āļđāļāđ€āļŠāļĢāļīāļĄāļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ– āđƒāļŠāđ‰āļ™āđ‰āļ­āļĒāļĨāļ‡āļ•āļąāđ‰āļ‡āđāļ•āđˆāļĄāļĩāļŪāļļāļ āđāļ•āđˆāļĒāļąāļ‡āļ„āļ‡āļžāļšāđ„āļ”āđ‰āđƒāļ™āđ„āļĨāļšāļĢāļēāļĢāļĩāļšāļēāļ‡āļ•āļąāļ§

jsx
// HOC that adds logging
function withLogging(WrappedComponent) {
  return function WithLogging(props) {
    useEffect(() => {
      console.log(`${WrappedComponent.name} mounted with props:`, props)

      return () => {
        console.log(`${WrappedComponent.name} unmounted`)
      }
    }, [])

    return <WrappedComponent {...props} />
  }
}

// HOC that handles authentication
function withAuth(WrappedComponent) {
  return function WithAuth(props) {
    const { user, isLoading } = useAuth()

    if (isLoading) return <LoadingSpinner />
    if (!user) return <Navigate to="/login" />

    return <WrappedComponent {...props} user={user} />
  }
}

// Usage
const ProtectedDashboard = withAuth(Dashboard)
const LoggedButton = withLogging(Button)

12. āļ­āļ˜āļīāļšāļēāļĒāļĢāļđāļ›āđāļšāļš Render Props

āļĢāļđāļ›āđāļšāļš Render Props āļŠāđˆāļ§āļĒāđāļšāđˆāļ‡āļ›āļąāļ™āļĨāļ­āļˆāļīāļāļĢāļ°āļŦāļ§āđˆāļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđ‚āļ”āļĒāļŠāđˆāļ‡āļœāđˆāļēāļ™ prop āļ—āļĩāđˆāđ€āļ›āđ‡āļ™āļŸāļąāļ‡āļāđŒāļŠāļąāļ™

jsx
// Component with render prop
function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 })

  useEffect(() => {
    const handleMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY })
    }

    window.addEventListener('mousemove', handleMove)
    return () => window.removeEventListener('mousemove', handleMove)
  }, [])

  // Call the render function with data
  return render(position)
}

// Usage
function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <div>
          Position: {x}, {y}
        </div>
      )}
    />
  )
}

// Modern version with custom hook (preferred)
function useMousePosition() {
  const [position, setPosition] = useState({ x: 0, y: 0 })

  useEffect(() => {
    const handleMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY })
    }

    window.addEventListener('mousemove', handleMove)
    return () => window.removeEventListener('mousemove', handleMove)
  }, [])

  return position
}

function App() {
  const { x, y } = useMousePosition()
  return <div>Position: {x}, {y}</div>
}

13. āļ§āļīāļ˜āļĩāļŠāļĢāđ‰āļēāļ‡ custom hook

Custom hook āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļšāđāļĒāļāđāļĨāļ°āļ™āļģāļĨāļ­āļˆāļīāļāļ—āļĩāđˆāļĄāļĩ state āđ„āļ›āđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļ™āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ•āđˆāļēāļ‡āđ†

useLocalStorage.jsjsx
function useLocalStorage(key, initialValue) {
  // Initialize with localStorage value or default
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key)
      return item ? JSON.parse(item) : initialValue
    } catch (error) {
      console.error(error)
      return initialValue
    }
  })

  // Setter wrapper that syncs with localStorage
  const setValue = useCallback((value) => {
    try {
      // Support update functions
      const valueToStore = value instanceof Function ? value(storedValue) : value
      setStoredValue(valueToStore)
      window.localStorage.setItem(key, JSON.stringify(valueToStore))
    } catch (error) {
      console.error(error)
    }
  }, [key, storedValue])

  return [storedValue, setValue]
}

// Usage
function Settings() {
  const [theme, setTheme] = useLocalStorage('theme', 'light')
  const [fontSize, setFontSize] = useLocalStorage('fontSize', 16)

  return (
    <div>
      <select value={theme} onChange={e => setTheme(e.target.value)}>
        <option value="light">Light</option>
        <option value="dark">Dark</option>
      </select>

      <input
        type="range"
        min="12"
        max="24"
        value={fontSize}
        onChange={e => setFontSize(Number(e.target.value))}
      />
    </div>
  )
}

14. āļĢāļđāļ›āđāļšāļš Compound Components āļ„āļ·āļ­āļ­āļ°āđ„āļĢ

āļĢāļđāļ›āđāļšāļšāļ™āļĩāđ‰āļŠāđˆāļ§āļĒāļŠāļĢāđ‰āļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļĩāđˆāļ—āļģāļ‡āļēāļ™āļĢāđˆāļ§āļĄāļāļąāļ™āđ‚āļ”āļĒāļ›āļĢāļīāļĒāļēāļĒ āļ„āļĨāđ‰āļēāļĒāļāļąāļšāļāļēāļĢāđƒāļŠāđ‰āđāļ—āđ‡āļ <select> āđāļĨāļ° <option>

jsx
// Shared context between components
const TabsContext = createContext()

function Tabs({ children, defaultValue }) {
  const [activeTab, setActiveTab] = useState(defaultValue)

  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  )
}

function TabList({ children }) {
  return <div className="tab-list" role="tablist">{children}</div>
}

function Tab({ value, children }) {
  const { activeTab, setActiveTab } = useContext(TabsContext)
  const isActive = activeTab === value

  return (
    <button
      role="tab"
      aria-selected={isActive}
      className={`tab ${isActive ? 'active' : ''}`}
      onClick={() => setActiveTab(value)}
    >
      {children}
    </button>
  )
}

function TabPanel({ value, children }) {
  const { activeTab } = useContext(TabsContext)

  if (activeTab !== value) return null

  return (
    <div role="tabpanel" className="tab-panel">
      {children}
    </div>
  )
}

// Attach sub-components
Tabs.List = TabList
Tabs.Tab = Tab
Tabs.Panel = TabPanel

// Intuitive usage
function App() {
  return (
    <Tabs defaultValue="profile">
      <Tabs.List>
        <Tabs.Tab value="profile">Profile</Tabs.Tab>
        <Tabs.Tab value="settings">Settings</Tabs.Tab>
        <Tabs.Tab value="billing">Billing</Tabs.Tab>
      </Tabs.List>

      <Tabs.Panel value="profile">Profile content...</Tabs.Panel>
      <Tabs.Panel value="settings">Settings content...</Tabs.Panel>
      <Tabs.Panel value="billing">Billing content...</Tabs.Panel>
    </Tabs>
  )
}

15. āļ§āļīāļ˜āļĩāļ™āļģāļĢāļđāļ›āđāļšāļš Controlled vs Uncontrolled āđ„āļ›āđƒāļŠāđ‰

āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļšāļš controlled āļĄāļĩ state āļ—āļĩāđˆāļ–āļđāļāļˆāļąāļ”āļāļēāļĢāđ‚āļ”āļĒ React āļŠāđˆāļ§āļ™āđāļšāļš uncontrolled āđƒāļŠāđ‰ DOM āđ‚āļ”āļĒāļ•āļĢāļ‡

jsx
// CONTROLLED component
// State is in React, component reflects that state
function ControlledInput() {
  const [value, setValue] = useState('')

  const handleSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted value:', value)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
      <button type="submit">Submit</button>
    </form>
  )
}

// UNCONTROLLED component
// State is in the DOM, we read it when needed
function UncontrolledInput() {
  const inputRef = useRef(null)

  const handleSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted value:', inputRef.current.value)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        ref={inputRef}
        defaultValue=""
      />
      <button type="submit">Submit</button>
    </form>
  )
}

// Component that supports BOTH modes
function FlexibleInput({ value, defaultValue, onChange }) {
  const isControlled = value !== undefined
  const [internalValue, setInternalValue] = useState(defaultValue || '')

  const currentValue = isControlled ? value : internalValue

  const handleChange = (e) => {
    if (!isControlled) {
      setInternalValue(e.target.value)
    }
    onChange?.(e.target.value)
  }

  return (
    <input
      type="text"
      value={currentValue}
      onChange={handleChange}
    />
  )
}

āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđāļĨāļ°āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

16. React.memo āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

React.memo āļ„āļ·āļ­ HOC āļ—āļĩāđˆāļ—āļģāļāļēāļĢ memoize āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđ€āļžāļ·āđˆāļ­āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđƒāļŦāļĄāđˆāļŦāļēāļ props āđ„āļĄāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡

jsx
// Memoized component
const ExpensiveList = React.memo(function ExpensiveList({ items, onItemClick }) {
  console.log('ExpensiveList rendered')

  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => onItemClick(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  )
})

// Parent using the memoized component
function Parent() {
  const [count, setCount] = useState(0)
  const [items] = useState([
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' }
  ])

  // ❌ This function is recreated on every render
  // So ExpensiveList re-renders despite memo
  const handleClick = (id) => console.log(id)

  // ✅ Stable function with useCallback
  const handleClickStable = useCallback((id) => {
    console.log(id)
  }, [])

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <ExpensiveList items={items} onItemClick={handleClickStable} />
    </div>
  )
}

// Custom comparison
const MemoWithCustomCompare = React.memo(
  function Component({ user, onClick }) {
    return <div onClick={onClick}>{user.name}</div>
  },
  (prevProps, nextProps) => {
    // Return true if props are equal (skip re-render)
    return prevProps.user.id === nextProps.user.id
  }
)

17. Code splitting āđāļĨāļ° React.lazy āļ„āļ·āļ­āļ­āļ°āđ„āļĢ

Code splitting āđāļšāđˆāļ‡āļšāļąāļ™āđ€āļ”āļīāļĨāļ­āļ­āļāđ€āļ›āđ‡āļ™ chunk āļ—āļĩāđˆāđ‚āļŦāļĨāļ”āļ•āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢ āļŠāđˆāļ§āļĒāļĨāļ”āđ€āļ§āļĨāļēāđƒāļ™āļāļēāļĢāđ‚āļŦāļĨāļ”āļ„āļĢāļąāđ‰āļ‡āđāļĢāļ

jsx
// Lazy loading components
const Dashboard = lazy(() => import('./Dashboard'))
const Settings = lazy(() => import('./Settings'))
const Profile = lazy(() => import('./Profile'))

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </Suspense>
  )
}

// Conditional lazy loading
function FeaturePanel({ showAdvanced }) {
  // Component is only loaded if needed
  const AdvancedOptions = lazy(() => import('./AdvancedOptions'))

  return (
    <div>
      <BasicOptions />

      {showAdvanced && (
        <Suspense fallback={<Skeleton />}>
          <AdvancedOptions />
        </Suspense>
      )}
    </div>
  )
}

// Named exports with lazy
const { Chart } = lazy(() =>
  import('./Charts').then(module => ({ default: module.Chart }))
)

18. āļ§āļīāļ˜āļĩāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĄāļĩāļ„āļ§āļēāļĄāļĒāļēāļ§āļĄāļēāļ

āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĒāļēāļ§āļĄāļēāļāļ­āļēāļˆāļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļ›āļąāļāļŦāļēāļ”āđ‰āļēāļ™āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž āļāļēāļĢāļ—āļģ virtualization āļˆāļ°āđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđ€āļ‰āļžāļēāļ°āļ­āļ‡āļ„āđŒāļ›āļĢāļ°āļāļ­āļšāļ—āļĩāđˆāļĄāļ­āļ‡āđ€āļŦāđ‡āļ™āđ„āļ”āđ‰

jsx
// With react-window (virtualization library)
import { FixedSizeList } from 'react-window'

function VirtualizedList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style} className="list-item">
      {items[index].name}
    </div>
  )

  return (
    <FixedSizeList
      height={400}
      width="100%"
      itemCount={items.length}
      itemSize={50}
    >
      {Row}
    </FixedSizeList>
  )
}

// Optimization without library: pagination
function PaginatedList({ items, pageSize = 20 }) {
  const [page, setPage] = useState(0)

  const paginatedItems = useMemo(() => {
    const start = page * pageSize
    return items.slice(start, start + pageSize)
  }, [items, page, pageSize])

  const totalPages = Math.ceil(items.length / pageSize)

  return (
    <div>
      <ul>
        {paginatedItems.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>

      <div className="pagination">
        <button
          onClick={() => setPage(p => p - 1)}
          disabled={page === 0}
        >
          Previous
        </button>
        <span>{page + 1} / {totalPages}</span>
        <button
          onClick={() => setPage(p => p + 1)}
          disabled={page >= totalPages - 1}
        >
          Next
        </button>
      </div>
    </div>
  )
}
āđ€āļāļ“āļ‘āđŒāļāļēāļĢāđƒāļŠāđ‰ virtualization

Virtualization āļˆāļ°āđ€āļĢāļīāđˆāļĄāļĄāļĩāļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒāđ€āļĄāļ·āđˆāļ­āļĢāļēāļĒāļāļēāļĢāļĄāļĩāļ­āļ‡āļ„āđŒāļ›āļĢāļ°āļāļ­āļšāđ€āļāļīāļ™āđ„āļĄāđˆāļāļĩāđˆāļĢāđ‰āļ­āļĒāļĢāļēāļĒāļāļēāļĢ āļŠāļģāļŦāļĢāļąāļšāļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāđ€āļĨāđ‡āļāļāļ§āđˆāļēāļ™āļąāđ‰āļ™ āļāļēāļĢāđƒāļŠāđ‰ pagination āļŦāļĢāļ·āļ­āļāļēāļĢāđ‚āļŦāļĨāļ”āđāļšāļšāļ—āļĒāļ­āļĒāļĄāļąāļāđ€āļžāļĩāļĒāļ‡āļžāļ­āđāļĨāđ‰āļ§

19. āļ§āļīāļ˜āļĩāļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāļ‹āđ‰āļģāļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™

āļāļēāļĢāļĢāļ°āļšāļļāđāļĨāļ°āļāļģāļˆāļąāļ”āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāļ‹āđ‰āļģāļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āđ€āļ›āđ‡āļ™āļŠāļīāđˆāļ‡āļŠāļģāļ„āļąāļāļ•āđˆāļ­āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž āļĄāļĩāđ€āļ—āļ„āļ™āļīāļ„āļŦāļĨāļēāļĒāļ­āļĒāđˆāļēāļ‡āļ—āļĩāđˆāļŠāđˆāļ§āļĒāļ›āļĢāļąāļšāļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđ„āļ”āđ‰

jsx
// Technique 1: Separate components
// ❌ Everything re-renders when count changes
function BadExample() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <ExpensiveComponent /> {/* Unnecessary re-render */}
    </div>
  )
}

// ✅ ExpensiveComponent no longer re-renders
function GoodExample() {
  return (
    <div>
      <Counter />
      <ExpensiveComponent />
    </div>
  )
}

function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}

// Technique 2: Pass children instead of rendering directly
// ✅ children is stable, no re-render of children
function ContextProvider({ children }) {
  const [value, setValue] = useState(0)

  return (
    <Context.Provider value={value}>
      {children} {/* children doesn't re-render when value changes */}
    </Context.Provider>
  )
}

// Technique 3: Use DevTools to identify re-renders
// React DevTools > Profiler > "Highlight updates when components render"

20. Automatic batching āđƒāļ™ React 18+ āļ„āļ·āļ­āļ­āļ°āđ„āļĢ

React 18 āļˆāļ°āļĢāļ§āļĄāļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• state āđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļīāđ€āļžāļ·āđˆāļ­āļĨāļ”āļˆāļģāļ™āļ§āļ™āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāļ‹āđ‰āļģ

jsx
// Before React 18: two re-renders
function handleClick() {
  setCount(c => c + 1) // Re-render
  setFlag(f => !f)      // Re-render
}

// React 18+: single re-render (automatic batching)
function handleClick() {
  setCount(c => c + 1) // Batched
  setFlag(f => !f)      // Batched
  // Single re-render at the end
}

// Even in async callbacks (React 18 novelty)
async function handleSubmit() {
  const response = await fetch('/api/submit')

  // These two updates are batched
  setData(response.data)
  setLoading(false)
  // Single re-render
}

// To force immediate re-render (rare)
import { flushSync } from 'react-dom'

function handleClick() {
  flushSync(() => {
    setCount(c => c + 1)
  })
  // DOM updated here

  flushSync(() => {
    setFlag(f => !f)
  })
  // DOM updated here
}

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React / Next.js āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

React āļŠāļĄāļąāļĒāđƒāļŦāļĄāđˆ (18+)

21. āļ­āļ˜āļīāļšāļēāļĒ useTransition āđāļĨāļ° useDeferredValue

āļŪāļļāļāļ—āļąāđ‰āļ‡āļŠāļ­āļ‡āļ™āļĩāđ‰āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļšāļ—āļģāđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļŦāļĄāļēāļĒāļ§āđˆāļēāļ­āļąāļ›āđ€āļ”āļ•āđƒāļ”āđ€āļ›āđ‡āļ™āđāļšāļšāđ„āļĄāđˆāđ€āļĢāđˆāļ‡āļ”āđˆāļ§āļ™ āđ€āļžāļ·āđˆāļ­āļĢāļąāļāļĐāļēāđƒāļŦāđ‰āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹āļ•āļ­āļšāļŠāļ™āļ­āļ‡āđ„āļ”āđ‰āļĢāļ§āļ”āđ€āļĢāđ‡āļ§

jsx
// useTransition: mark an update as non-urgent
function SearchResults() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])
  const [isPending, startTransition] = useTransition()

  const handleChange = (e) => {
    // Urgent update: input stays responsive
    setQuery(e.target.value)

    // Non-urgent update: can be interrupted
    startTransition(() => {
      const filtered = filterLargeDataset(e.target.value)
      setResults(filtered)
    })
  }

  return (
    <div>
      <input value={query} onChange={handleChange} />

      {isPending && <span>Searching...</span>}

      <ul>
        {results.map(r => <li key={r.id}>{r.name}</li>)}
      </ul>
    </div>
  )
}

// useDeferredValue: defer a value
function DeferredSearch() {
  const [query, setQuery] = useState('')
  // deferredQuery is "behind" during rapid updates
  const deferredQuery = useDeferredValue(query)

  // Show indicator during the "lag"
  const isStale = query !== deferredQuery

  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />

      <div style={{ opacity: isStale ? 0.5 : 1 }}>
        {/* Uses deferred value, fewer calculations */}
        <ExpensiveList filter={deferredQuery} />
      </div>
    </div>
  )
}

22. Suspense āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

Suspense āļˆāļąāļ”āļāļēāļĢāļŠāļ–āļēāļ™āļ°āļāļēāļĢāđ‚āļŦāļĨāļ”āđƒāļ™āļĢāļđāļ›āđāļšāļšāđ€āļŠāļīāļ‡āļ›āļĢāļ°āļāļēāļĻ āđāļĨāļ°āļ•āļąāđ‰āļ‡āđāļ•āđˆ React 18+ āļŠāļēāļĄāļēāļĢāļ–āđƒāļŠāđ‰āļāļąāļšāļāļēāļĢāļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāđ„āļ”āđ‰

With a compatible library (React Query, Relay, etc.)jsx
function UserProfile({ userId }) {
  return (
    <Suspense fallback={<ProfileSkeleton />}>
      <ProfileContent userId={userId} />
    </Suspense>
  )
}

// The component "suspends" during loading
function ProfileContent({ userId }) {
  // This function suspends if data isn't ready
  const user = useUserData(userId)

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </div>
  )
}

// Nested Suspense boundaries
function Dashboard() {
  return (
    <Suspense fallback={<DashboardSkeleton />}>
      <Header />

      <div className="grid">
        <Suspense fallback={<StatsSkeleton />}>
          <Stats />
        </Suspense>

        <Suspense fallback={<ChartSkeleton />}>
          <Chart />
        </Suspense>

        <Suspense fallback={<TableSkeleton />}>
          <RecentActivity />
        </Suspense>
      </div>
    </Suspense>
  )
}

23. useActionState (React 19) āļ„āļ·āļ­āļ­āļ°āđ„āļĢ

useActionState (āļŠāļ·āđˆāļ­āđ€āļ”āļīāļĄ useFormState) āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļŸāļ­āļĢāđŒāļĄāļĢāđˆāļ§āļĄāļāļąāļš Server Action āļ‡āđˆāļēāļĒāļ‚āļķāđ‰āļ™

actions.jsjsx
'use server'

async function submitForm(prevState, formData) {
  const email = formData.get('email')
  const password = formData.get('password')

  // Validation
  if (!email || !password) {
    return { error: 'All fields are required' }
  }

  try {
    await createUser({ email, password })
    return { success: true, message: 'Account created!' }
  } catch (e) {
    return { error: e.message }
  }
}

// Component
function SignupForm() {
  const [state, formAction, isPending] = useActionState(submitForm, {})

  return (
    <form action={formAction}>
      {state.error && (
        <div className="error">{state.error}</div>
      )}

      {state.success && (
        <div className="success">{state.message}</div>
      )}

      <input name="email" type="email" placeholder="Email" />
      <input name="password" type="password" placeholder="Password" />

      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create account'}
      </button>
    </form>
  )
}

24. Server Component āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

Server Component āļ—āļģāļ‡āļēāļ™āļšāļ™āđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒāđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™ āļ—āļģāđƒāļŦāđ‰āļĨāļ”āļ›āļĢāļīāļĄāļēāļ“ JavaScript āļ—āļĩāđˆāļŠāđˆāļ‡āđ„āļ›āļĒāļąāļ‡āđ„āļ„āļĨāđ€āļ­āļ™āļ•āđŒāđ„āļ”āđ‰

ServerComponent.jsxjsx
// No "use client" = Server Component by default
import { prisma } from '@/lib/prisma'

// async/await directly in the component
export default async function ProductList() {
  // Direct database call (no API)
  const products = await prisma.product.findMany({
    orderBy: { createdAt: 'desc' },
    take: 10
  })

  return (
    <div>
      <h2>Recent Products</h2>
      <ul>
        {products.map(product => (
          <li key={product.id}>
            {product.name} - ${product.price}
            {/* Can include Client Components */}
            <AddToCartButton productId={product.id} />
          </li>
        ))}
      </ul>
    </div>
  )
}

// AddToCartButton.jsx
'use client'

// This component needs interactivity
export function AddToCartButton({ productId }) {
  const [isPending, startTransition] = useTransition()

  const handleClick = () => {
    startTransition(async () => {
      await addToCart(productId)
    })
  }

  return (
    <button onClick={handleClick} disabled={isPending}>
      {isPending ? '...' : 'Add'}
    </button>
  )
}

25. āļ­āļ˜āļīāļšāļēāļĒ SSR streaming āđƒāļ™ React 18

SSR streaming āļˆāļ°āļŠāđˆāļ‡ HTML āđ„āļ›āļĒāļąāļ‡āđ€āļšāļĢāļēāļ§āđŒāđ€āļ‹āļ­āļĢāđŒāļ­āļĒāđˆāļēāļ‡āļ„āđˆāļ­āļĒāđ€āļ›āđ‡āļ™āļ„āđˆāļ­āļĒāđ„āļ› āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āļĢāļ­āđƒāļŦāđ‰āļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđ€āļŠāļĢāđ‡āļˆāļŠāļĄāļšāļđāļĢāļ“āđŒāļāđˆāļ­āļ™

app/page.jsx (Next.js App Router)jsx
import { Suspense } from 'react'

export default function Page() {
  return (
    <div>
      {/* Immediate render */}
      <Header />

      {/* Streamed when ready */}
      <Suspense fallback={<MainContentSkeleton />}>
        <MainContent />
      </Suspense>

      {/* Streamed independently */}
      <Suspense fallback={<SidebarSkeleton />}>
        <Sidebar />
      </Suspense>

      {/* Immediate render */}
      <Footer />
    </div>
  )
}

// The browser receives:
// 1. HTML shell with Header, skeletons, Footer
// 2. MainContent when its request completes
// 3. Sidebar when its request completes

// loading.jsx for route-level streaming
export default function Loading() {
  return <PageSkeleton />
}

āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ state

26. āđ€āļĄāļ·āđˆāļ­āđƒāļ”āļ„āļ§āļĢāđƒāļŠāđ‰ Redux, Context API āļŦāļĢāļ·āļ­āļ—āļēāļ‡āđ€āļĨāļ·āļ­āļāļ­āļ·āđˆāļ™

āļāļēāļĢāđ€āļĨāļ·āļ­āļāļ‚āļķāđ‰āļ™āļ­āļĒāļđāđˆāļāļąāļšāļ„āļ§āļēāļĄāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āļ‚āļ­āļ‡ state āđāļĨāļ°āļ„āļ§āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ‚āļ­āļ‡āđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒ

jsx
// Context API: simple state, few updates
// ✅ Good for: theme, user, preferences
const ThemeContext = createContext()

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

// Redux / Zustand: complex state, frequent updates
// ✅ Good for: cart, filters, complex business data
import { create } from 'zustand'

const useCartStore = create((set, get) => ({
  items: [],
  total: 0,

  addItem: (product) => set((state) => {
    const existing = state.items.find(i => i.id === product.id)
    if (existing) {
      return {
        items: state.items.map(i =>
          i.id === product.id ? { ...i, quantity: i.quantity + 1 } : i
        )
      }
    }
    return { items: [...state.items, { ...product, quantity: 1 }] }
  }),

  removeItem: (id) => set((state) => ({
    items: state.items.filter(i => i.id !== id)
  })),

  getTotal: () => get().items.reduce((sum, i) => sum + i.price * i.quantity, 0)
}))

// React Query / SWR: server state (cache, refetch)
// ✅ Good for: API data, server synchronization
import { useQuery, useMutation } from '@tanstack/react-query'

function Products() {
  const { data, isLoading } = useQuery({
    queryKey: ['products'],
    queryFn: () => fetch('/api/products').then(r => r.json())
  })

  const mutation = useMutation({
    mutationFn: (newProduct) => fetch('/api/products', {
      method: 'POST',
      body: JSON.stringify(newProduct)
    })
  })
}

27. āļ§āļīāļ˜āļĩāļ™āļģāļĢāļđāļ›āđāļšāļš Reducer āđ„āļ›āđƒāļŠāđ‰

āļĢāļđāļ›āđāļšāļš Reducer āđƒāļŠāđ‰āļĢāļ§āļĄāļĻāļđāļ™āļĒāđŒāļĨāļ­āļˆāļīāļāļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• state āļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āđ„āļ§āđ‰āđƒāļ™āļ—āļĩāđˆāđ€āļ”āļĩāļĒāļ§

jsx
// Define actions
const ACTIONS = {
  ADD_TODO: 'ADD_TODO',
  TOGGLE_TODO: 'TOGGLE_TODO',
  DELETE_TODO: 'DELETE_TODO',
  SET_FILTER: 'SET_FILTER'
}

// Pure reducer (no side effects)
function todoReducer(state, action) {
  switch (action.type) {
    case ACTIONS.ADD_TODO:
      return {
        ...state,
        todos: [
          ...state.todos,
          { id: Date.now(), text: action.payload, completed: false }
        ]
      }

    case ACTIONS.TOGGLE_TODO:
      return {
        ...state,
        todos: state.todos.map(todo =>
          todo.id === action.payload
            ? { ...todo, completed: !todo.completed }
            : todo
        )
      }

    case ACTIONS.DELETE_TODO:
      return {
        ...state,
        todos: state.todos.filter(todo => todo.id !== action.payload)
      }

    case ACTIONS.SET_FILTER:
      return { ...state, filter: action.payload }

    default:
      return state
  }
}

// Usage with useReducer
function TodoApp() {
  const [state, dispatch] = useReducer(todoReducer, {
    todos: [],
    filter: 'all'
  })

  const addTodo = (text) => {
    dispatch({ type: ACTIONS.ADD_TODO, payload: text })
  }

  const toggleTodo = (id) => {
    dispatch({ type: ACTIONS.TOGGLE_TODO, payload: id })
  }

  const filteredTodos = useMemo(() => {
    switch (state.filter) {
      case 'completed':
        return state.todos.filter(t => t.completed)
      case 'active':
        return state.todos.filter(t => !t.completed)
      default:
        return state.todos
    }
  }, [state.todos, state.filter])

  return (
    <div>
      <TodoForm onAdd={addTodo} />
      <TodoList todos={filteredTodos} onToggle={toggleTodo} />
      <FilterButtons
        current={state.filter}
        onChange={(f) => dispatch({ type: ACTIONS.SET_FILTER, payload: f })}
      />
    </div>
  )
}

āļāļēāļĢāļ—āļ”āļŠāļ­āļš

28. āļ§āļīāļ˜āļĩāļ—āļ”āļŠāļ­āļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ React

āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļšāļ•āļĢāļ§āļˆāļŠāļ­āļšāļāļēāļĢāđ€āļĢāļ™āđ€āļ”āļ­āļĢāđŒāđāļĨāļ°āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļ‚āļ­āļ‡āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹

Button.test.jsxjsx
import { render, screen, fireEvent } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Button from './Button'

describe('Button', () => {
  // Basic rendering test
  it('renders with correct text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByRole('button')).toHaveTextContent('Click me')
  })

  // Interaction test
  it('calls onClick when clicked', async () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click</Button>)

    await userEvent.click(screen.getByRole('button'))

    expect(handleClick).toHaveBeenCalledTimes(1)
  })

  // Disabled state test
  it('does not call onClick when disabled', async () => {
    const handleClick = jest.fn()
    render(<Button disabled onClick={handleClick}>Click</Button>)

    await userEvent.click(screen.getByRole('button'))

    expect(handleClick).not.toHaveBeenCalled()
  })

  // Async state test
  it('shows loading state', async () => {
    render(<Button isLoading>Submit</Button>)

    expect(screen.getByRole('button')).toBeDisabled()
    expect(screen.getByTestId('spinner')).toBeInTheDocument()
  })
})

// Testing a custom hook
import { renderHook, act } from '@testing-library/react'
import useCounter from './useCounter'

describe('useCounter', () => {
  it('increments counter', () => {
    const { result } = renderHook(() => useCounter(0))

    act(() => {
      result.current.increment()
    })

    expect(result.current.count).toBe(1)
  })
})

29. āļ§āļīāļ˜āļĩ mock āļāļēāļĢāđ€āļĢāļĩāļĒāļ API āđƒāļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļš

Mock āļŠāđˆāļ§āļĒāđāļĒāļāļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ­āļ­āļāļˆāļēāļāļāļēāļĢāļžāļķāđˆāļ‡āļžāļēāļ āļēāļĒāļ™āļ­āļ

jsx
// With MSW (Mock Service Worker) - recommended
import { setupServer } from 'msw/node'
import { http, HttpResponse } from 'msw'

const server = setupServer(
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ])
  }),

  http.post('/api/users', async ({ request }) => {
    const body = await request.json()
    return HttpResponse.json({ id: 3, ...body }, { status: 201 })
  })
)

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

test('loads and displays users', async () => {
  render(<UserList />)

  expect(screen.getByText('Loading...')).toBeInTheDocument()

  await waitFor(() => {
    expect(screen.getByText('Alice')).toBeInTheDocument()
    expect(screen.getByText('Bob')).toBeInTheDocument()
  })
})

// Override for a specific test
test('handles error state', async () => {
  server.use(
    http.get('/api/users', () => {
      return HttpResponse.json({ error: 'Server error' }, { status: 500 })
    })
  )

  render(<UserList />)

  await waitFor(() => {
    expect(screen.getByText('Loading error')).toBeInTheDocument()
  })
})

30. āļ§āļīāļ˜āļĩāļˆāļąāļ”āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļšāđ€āļžāļ·āđˆāļ­āļ„āļ§āļēāļĄāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļŠāļĄ

āļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ—āļĩāđˆāļŠāļĄāļ”āļļāļĨāļ„āļ§āļĢāļĢāļ§āļĄāļāļēāļĢāļ—āļ”āļŠāļ­āļšāđƒāļ™āļĢāļ°āļ”āļąāļšāļ•āđˆāļēāļ‡āđ† āđ€āļ‚āđ‰āļēāļ”āđ‰āļ§āļĒāļāļąāļ™

jsx
// Recommended testing pyramid:
// - Many unit tests (fast, isolated)
// - Some integration tests (components + hooks)
// - Few E2E tests (critical scenarios)

// Unit tests: pure logic
// utils/formatPrice.test.js
describe('formatPrice', () => {
  it('formats with 2 decimals', () => {
    expect(formatPrice(10)).toBe('$10.00')
  })

  it('handles zero', () => {
    expect(formatPrice(0)).toBe('$0.00')
  })
})

// Integration tests: complete component
// features/Checkout/Checkout.test.jsx
describe('Checkout', () => {
  it('completes purchase flow', async () => {
    render(
      <CartProvider>
        <Checkout />
      </CartProvider>
    )

    // Fill the form
    await userEvent.type(screen.getByLabelText('Email'), 'test@example.com')
    await userEvent.type(screen.getByLabelText('Card'), '4242424242424242')

    // Submit
    await userEvent.click(screen.getByRole('button', { name: 'Pay' }))

    // Verify result
    await waitFor(() => {
      expect(screen.getByText('Order confirmed')).toBeInTheDocument()
    })
  })
})

// E2E tests with Playwright
// e2e/checkout.spec.ts
test('user can complete checkout', async ({ page }) => {
  await page.goto('/products')
  await page.click('[data-testid="add-to-cart-1"]')
  await page.click('[data-testid="checkout-button"]')

  await page.fill('[name="email"]', 'test@example.com')
  await page.fill('[name="card"]', '4242424242424242')
  await page.click('button[type="submit"]')

  await expect(page.locator('text=Order confirmed')).toBeVisible()
})

āļšāļ—āļŠāļĢāļļāļ›

āļ„āļģāļ–āļēāļĄāļ—āļąāđ‰āļ‡ 30 āļ‚āđ‰āļ­āļ™āļĩāđ‰āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļ„āļ§āļēāļĄāļĢāļđāđ‰ React āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ āļ‚āļ­āļšāđ€āļ‚āļ•āļŦāļĨāļąāļāļ—āļĩāđˆāļ„āļ§āļĢāđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļ āđ„āļ”āđ‰āđāļāđˆ

  • ✅ āļžāļ·āđ‰āļ™āļāļēāļ™: Virtual DOM, JSX, props āļāļąāļš state, āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ
  • ✅ Hooks: useState, useEffect, useMemo, useCallback, useRef, useContext
  • ✅ āļĢāļđāļ›āđāļšāļš: HOC, Render Props, Compound Components, custom hooks
  • ✅ āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž: React.memo, lazy loading, virtualization
  • ✅ React āļŠāļĄāļąāļĒāđƒāļŦāļĄāđˆ: Suspense, Transitions, Server Components
  • ✅ āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ state: Context, Redux/Zustand, React Query
  • ✅ āļāļēāļĢāļ—āļ”āļŠāļ­āļš: React Testing Library, mocks, āļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāļ—āļ”āļŠāļ­āļš

āļāļēāļĢāđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āļŠāļąāļĄāļ āļēāļĐāļ“āđŒ React āđ„āļĄāđˆāđ„āļ”āđ‰āđ€āļ›āđ‡āļ™āđ€āļžāļĩāļĒāļ‡āļāļēāļĢāļ—āđˆāļ­āļ‡āļˆāļģ āļāļēāļĢāļāļķāļāļāļ™āļˆāļēāļāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒāļˆāļĢāļīāļ‡āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āđāļ™āļ§āļ„āļīāļ”āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļāļąāļ‡āđāļ™āđˆāļ™ āđāļĨāļ°āļ­āļ˜āļīāļšāļēāļĒāđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ€āļ›āđ‡āļ™āļ˜āļĢāļĢāļĄāļŠāļēāļ•āļīāđƒāļ™āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āđāļ—āđ‡āļ

#react interview
#frontend interview
#react questions
#javascript
#technical interview

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

React 19 useEffectEvent and Activity API

React 19 useEffectEvent āđāļĨāļ° Activity: API āđƒāļŦāļĄāđˆāļžāļĢāđ‰āļ­āļĄāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ 2026

āđ€āļˆāļēāļ°āļĨāļķāļ useEffectEvent āđāļĨāļ° Activity component āđƒāļ™ React 19.2 āđāļāđ‰āļ›āļąāļāļŦāļē stale closure, pre-rendering āđ€āļšāļ·āđ‰āļ­āļ‡āļŦāļĨāļąāļ‡ āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

Cache Components āđƒāļ™ Next.js 16: use cache, PPR āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

Cache Components āđƒāļ™ Next.js 16 āļ›āļĩ 2026: āļ„āļđāđˆāļĄāļ·āļ­āļ„āļĢāļšāļ–āđ‰āļ§āļ™ use cache, PPR āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

āļ„āļđāđˆāļĄāļ·āļ­āđ€āļŠāļīāļ‡āļĨāļķāļāđ€āļāļĩāđˆāļĒāļ§āļāļąāļš Cache Components āđƒāļ™ Next.js 16: directive use cache āļ—āļąāđ‰āļ‡āļŠāļēāļĄāļĢāļ°āļ”āļąāļš, Partial Pre-Rendering, cacheLife profiles, cacheTag, āļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāļ‚āļ­āļ‡ cache āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļŠāļģāļŦāļĢāļąāļš developer āđƒāļ™āļ›āļĩ 2026

React Compiler 2026 memoization āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļīāđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

React Compiler āđƒāļ™āļ›āļĩ 2026: Automatic Memoization āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ React Compiler āļ—āļĩāđˆāļ—āļģ memoization āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļĒāļ­āļ”āļ™āļīāļĒāļĄāļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē React āđƒāļ™āļ›āļĩ 2026