Гузариш ба мундариҷа
Мавзӯи 10 аз 13
Назария

Хукҳои худ ва бор кардани маълумот

Хукҳои худ

Хукҳои useState, useEffect, useRef, useContext — хиштҳо мебошанд. Аз онҳо хукҳои худро ҷамъ кардан мумкин аст. Хуки худ — функсияи оддӣ аст, ки:

  • бо use ном дорад (useToggle, useWindowWidth, useFetch);
  • дар дохил хукҳои дигарро даъват мекунад.

Барои чӣ? Барои ҷудо кардани мантиқ аз компонент ва истифодаи он дар якчанд ҷой. Муқоиса кунед:

// Буд: мантиқи андозаи равзана рост дар компонент
function Header() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  return width < 600 ? <MobileMenu /> : <DesktopMenu />;
}
// Шуд: мантиқ дар хук, компонент бо як нигоҳ хонда мешавад
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  return width;
}

function Header() {
  const width = useWindowWidth();
  return width < 600 ? <MobileMenu /> : <DesktopMenu />;
}

function Sidebar() {
  const width = useWindowWidth();   // ҳамон мантиқ боз дар як ҷой
  return width < 900 ? null : <aside>…</aside>;
}

Муҳим: хукҳо мантиқ-ро тақсим мекунанд, на ҳолат-ро. Ҳар даъвати useWindowWidth() ҳолати худ ва обунаи худро месозад — гӯё код рост ба компонент гузошта шуда бошад. Барои он ки компонентҳои гуногун ҳамон як маълумотро тақсим кунанд, контекст (ё волиди умумӣ) лозим аст.

Қоидаҳои хукҳо барои хукҳои худ ҳам амал мекунанд: танҳо дар сатҳи болоии компонент ё хуки дигар даъват кардан, на дар дохили шартҳо ва давраҳо. Номи бо use — танҳо анъана нест: аз рӯи он React ва линтер мефаҳманд, ки функсияро бояд аз рӯи ҳамин қоидаҳо санҷид.

Бор кардани маълумот: се ҳолат

Бор кардан аз сервер — эффекти маъмултарин аст. Вай ҳамеша се ҳолат дорад, ва ҳар кадомашро нишон додан лозим аст:

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function load() {
      try {
        const response = await fetch("https://api.example.com/products");
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        setProducts(await response.json());
      } catch (e) {
        setError(e.message);
      } finally {
        setLoading(false);
      }
    }
    load();
  }, []);

  if (loading) return <p>Боркунӣ…</p>;
  if (error) return <p className="error">Бор кардан нашуд: {error}</p>;
  return (
    <ul>
      {products.map((p) => <li key={p.id}>{p.title}</li>)}
    </ul>
  );
}

Ин ҷо чӣ муҳим аст:

  • функсияи эффектро async кардан мумкин нест: useEffect(async () => …) промис бармегардонад, вале React аз эффект ё ҳеҷ чиз, ё функсияи тозакуниро интизор аст. Барои ҳамин дар дохил async function load()-ро эълон карда, фавран даъват мекунанд;
  • response.ok-ро худамон месанҷем: fetch ҷавоби 404 ё 500-ро хато намешуморад (мавзӯъ дар бораи fetch дар курси JavaScript);
  • finally нишондиҳандаи боркуниро дар ҳар ҳолат хомӯш мекунад.

Бор кардан ҳангоми тағйири параметрҳо

Агар суроға аз props ё ҳолат вобаста бошад, онро дар вобастагиҳо нишон медиҳанд — ва эффект ҳангоми ҳар тағйир аз нав оғоз мешавад:

function UserPage({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    setUser(null);                    // кӯҳнаро тоза кардан, то нав бор мешавад
    fetch(`https://api.example.com/users/${userId}`)
      .then((r) => r.json())
      .then(setUser);
  }, [userId]);

  if (!user) return <p>Боркунӣ…</p>;
  return <h1>{user.name}</h1>;
}

Пойгаи ҷавобҳо

Дар ин код хатое пинҳон аст, ки дар бисёр барномаҳо ҳаст. Корбар зуд профили Аняро кушод, баъд Тимурро. Ду дархост рафт. Ҷавобҳо бо ҳар тартиб меоянд: агар сервер дар бораи Аня дертар аз Тимур ҷавоб дод, дар саҳифаи Тимур Аня пайдо мешавад.

Ҳал — функсияи тозакунии эффект. Пеш аз оғози такрории эффект (ва ҳангоми нест кардани компонент) React тозакунии эффекти кӯҳна-ро даъват мекунад. Дар он қайд мекунем, ки ҷавоби кӯҳна дигар лозим нест:

useEffect(() => {
  let ignore = false;

  async function load() {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const data = await response.json();
    if (!ignore) setUser(data);       // эффекти кӯҳна аллакай «хомӯш» — ҳолатро даст намезанем
  }
  load();

  return () => {
    ignore = true;
  };
}, [userId]);

Ҳар оғози эффект тағйирёбандаи ignore-и худро дорад (closure!). Вақте userId тағйир меёбад, тозакунӣ ба оғози кӯҳна ignore = true мегузорад, ва ҷавоби он, кай ки наояд, гузаронида мешавад.

Боз беҳтар — худи дархостро бекор кардан, то трафикро сарф накунем. Барои ин fetch AbortController дорад:

useEffect(() => {
  const controller = new AbortController();
  fetch(url, { signal: controller.signal })
    .then((r) => r.json())
    .then(setData)
    .catch((e) => {
      if (e.name !== "AbortError") setError(e.message);
    });
  return () => controller.abort();   // ҳангоми иваз шудани url ё рафтан аз саҳифа дархостро бекор мекунем
}, [url]);

Хуки useFetch

Ҳамааш якҷоя ба хуки худ хуб ҷой мегирад — ва компонентҳо хеле содда мешаванд:

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let ignore = false;
    async function load() {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const json = await response.json();
        if (!ignore) setData(json);
      } catch (e) {
        if (!ignore) setError(e.message);
      } finally {
        if (!ignore) setLoading(false);
      }
    }
    load();
    return () => {
      ignore = true;
    };
  }, [url]);

  return { data, loading, error };
}

function Weather({ city }) {
  const { data, loading, error } = useFetch(`https://api.example.com/weather?city=${city}`);
  if (loading) return <p>Боркунӣ…</p>;
  if (error) return <p>Хато: {error}</p>;
  return <p>{city}: {data.temp}°</p>;
}

Дар лоиҳаҳои калон чӣ истифода мебаранд

useFetch-и худ барои фаҳмидан ва барномаҳои хурд хуб аст. Дар лоиҳаҳои калон бор кардани маълумотро одатан ба китобхонаи TanStack Query (React Query) ё SWR месупоранд: онҳо кэш (кушодани такрории саҳифа — фаврӣ), кӯшишҳои такрорӣ, навсозӣ ҳангоми баргаштан ба ҷадвалакро илова мекунанд. Онҳо бо ҳамон нақша сохта шудаанд: хуке, ки data, isLoading ва error-ро бармегардонад.

Фреймворкҳо, мисли Next.js, бошанд, маълумотро ҳатто дар сервер, пеш аз он ки саҳифа ба браузер ояд, бор карда метавонанд.

Хулоса

  • Хуки худ — функсияи useЧизе, ки хукҳои дигарро даъват мекунад. Мантиқро тақсим мекунад, на ҳолатро.
  • Бор кардан: ҳолатҳои loading, data, error; функсияи эффектро async намекунанд — дар дохил async function load()-ро эълон мекунанд.
  • Параметрҳои дархост — дар вобастагиҳои эффект.
  • Пойгаи ҷавобҳо: let ignore = false + тозакунии () => { ignore = true }, ё AbortController.
  • Дар лоиҳаҳои калон — TanStack Query ё SWR.

Хуки useToggle

Осон+10 XP

Хуки худи useToggle(initial)-ро нависед. Вай қимати мантиқиро нигоҳ медорад (агар initial дода нашуда бошад — false) ва массиви [value, toggle]-ро бармегардонад, ки дар он toggle() қиматро ба муқобил иваз мекунад.

function Menu() {
  const [open, toggle] = useToggle();
  return <button onClick={toggle}>{open ? "Close" : "Open"}</button>;
}

Барои ҳал кардани масъалаҳо коннекторро пайваст кун

Коди масъалаҳо дар компютери худат иҷро мешавад — ин аз браузер тезтар ва боэътимодтар аст. Барои ин барномаи ройгони коннектори CodeWithMe лозим аст. Онро як бор пайваст кардан кифоя аст.

Коннекторро дар ин компютер ҷустуҷӯ мекунем…

  1. 1
    Коннекторро барои системаи худ (Windows, macOS ё Linux) зеркашӣ кун.Зеркашии коннекторДар саҳифаи зеркашӣ файлеро интихоб кун, ки дар номаш системаи ту ҳаст, масалан windows-amd64.
  2. 2Онро иҷро кун ва ҷузвдонеро интихоб кун, ки ҳалҳоят дар он ҷо меистанд. Python ва Node.js-ро ӯ худаш ҳангоми зарурат ба он ҷо мегузорад.
  3. 3
    Дар поён рамзи 6-рақамаро ворид кун — он дар равзанаи коннектор навишта шудааст («Рамз барои сайти CodeWithMe»). Агар браузер дар бораи дастрасӣ ба шабакаи маҳаллӣ пурсад — иҷозат деҳ.

Коннектор кушода аст (рамзи манбаъ дар GitHub), танҳо дар компютери ту кор мекунад ва кодро танҳо пас аз ворид кардани рамзи пайвастшавӣ иҷро мекунад.