React / useContext hook

useContext hook

Props дамжуулах нь нэг, хоёр түвшинд тохиромжтой. Гэвч апп томрох тусам App → Layout → Sidebar → UserMenu → Avatar гэх мэт олон давхаргаар нэг зүйлийг дамжуулах шаардлага гардаг. Энийг prop drilling гэнэ — утгыг зөвхөн дамжуулахын тулд дунд компонентуудаар "өрөмдөж" ордог учраас. useContext hook энэ асуудлыг шийддэг — өгөгдлийг шууд хэрэгтэй component-д хүргэдэг.

Context үүсгэх

Context ашиглахад гурван алхам байдаг: үүсгэх, Provider-ээр боох, унших:

jsx
// context/ThemeContext.jsx
import { createContext } from "react";

// 1. Context үүсгэнэ — default утга өгч болно
const ThemeContext = createContext("dark");

export default ThemeContext;
jsx
// App.jsx
import { useState } from "react";
import ThemeContext from "./context/ThemeContext";
import Page from "./components/Page";

function App() {
  const [theme, setTheme] = useState("dark");

  // 2. Provider-ээр хүүхэд component-уудыг боодог
  return (
    <ThemeContext.Provider value={theme}>
      <button
        onClick={() => setTheme((t) => (t === "dark" ? "light" : "dark"))}
      >
        Загвар солих
      </button>
      <Page />
    </ThemeContext.Provider>
  );
}
jsx
// components/Avatar.jsx — хэд хэдэн түвшний доор байгаа ч шууд авна
import { useContext } from "react";
import ThemeContext from "../context/ThemeContext";

function Avatar() {
  // 3. useContext ашиглан унших
  const theme = useContext(ThemeContext);

  return (
    <div style={{ background: theme === "dark" ? "#0f172a" : "#f1f5f9" }}>
      Профайл
    </div>
  );
}

Providervalue-д дамжуулсан утга нь доорх бүх component-д ямар ч props дамжуулалтгүйгээр хүрнэ.

Хэрэглэгчийн мэдээлэл дамжуулах

Нэвтэрсэн хэрэглэгчийн мэдээллийг апп даяар хуваалцах хамгийн нийтлэг хэрэглээ:

jsx
// context/UserContext.jsx
import { createContext, useContext, useState } from "react";

const UserContext = createContext(null);

// Provider component — логикийг хамт хадгална
export function UserProvider({ children }) {
  const [user, setUser] = useState(null);

  function login(userData) {
    setUser(userData);
  }

  function logout() {
    setUser(null);
  }

  return (
    <UserContext.Provider value={{ user, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}

// Custom hook — хялбар унших
export function useUser() {
  return useContext(UserContext);
}
jsx
// App.jsx
import { UserProvider } from "./context/UserContext";

function App() {
  return (
    <UserProvider>
      <Navbar />
      <Main />
    </UserProvider>
  );
}
jsx
// components/Navbar.jsx
import { useUser } from "../context/UserContext";

function Navbar() {
  const { user, logout } = useUser();

  return (
    <nav>
      {user ? (
        <>
          <span>{user.username}</span>
          <button onClick={logout}>Гарах</button>
        </>
      ) : (
        <a href="/login">Нэвтрэх</a>
      )}
    </nav>
  );
}

Олон Context хослуулах

Нэг аппад хэд хэдэн context хамт ажиллаж болно:

jsx
// App.jsx
import { ThemeProvider } from "./context/ThemeContext";
import { UserProvider } from "./context/UserContext";
import { LanguageProvider } from "./context/LanguageContext";

function App() {
  return (
    <UserProvider>
      <ThemeProvider>
        <LanguageProvider>
          <Router />
        </LanguageProvider>
      </ThemeProvider>
    </UserProvider>
  );
}
jsx
// Дурын component дотор хэдэн context-аас ч унших боломжтой
function SettingsPage() {
  const { user } = useUser();
  const { theme, setTheme } = useTheme();
  const { language, setLanguage } = useLanguage();

  return (
    <div>
      <h2>{user.username}-н тохиргоо</h2>
      <select value={theme} onChange={(e) => setTheme(e.target.value)}>
        <option value="dark">Харанхуй</option>
        <option value="light">Цайвар</option>
      </select>
    </div>
  );
}

Context хэзээ ашиглах вэ?

Context бол хүчирхэг боловч хэрэв буруу ашиглавал апп удааширдаг — Provider-н value өөрчлөгдөх бүрт дотор бүх component дахин рендер болдог:

jsx
// ❌ Буруу — объект literal шууд value-д байвал рендер болгонд шинэ объект үүснэ
<UserContext.Provider value={{ user, login, logout }}>

// ✅ Зөв — useMemo ашиглан object-г тогтворжуулна
import { useMemo } from 'react'

function UserProvider({ children }) {
  const [user, setUser] = useState(null)

  const value = useMemo(() => ({
    user,
    login: (data) => setUser(data),
    logout: () => setUser(null),
  }), [user])

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

Context-г ашиглах нь зөв тохиолдол: theme, хэрэглэгчийн мэдээлэл, хэлний тохиргоо, глобал modal/toast. Хэрэв өгөгдөл хоёр, гурав л түвшин дамжих бол энгийн props хангалттай.

Дараагийн хичээлд:

useReducer hook ашиглан нарийн төвөгтэй state логикийг зохион байгуулах аргыг судална. useState-с хэзээ шилжих, reducer функц бичих аргыг жишээгээр ойлгоно.