هوک useContext (useContext)
هوک useContext در ری اکت کمک می کند یک داده مشترک را بین چند کامپوننت عمیق پخش کنی، بدون این که مجبور شوی آن را از هر پدر به فرزند با props رد کنی.
React Context چیست؟
ری اکت کانتکست (React Context) یعنی یک انبار داده مشترک. این انبار بالای درخت کامپوننت ها قرار می گیرد و بچه ها می توانند مستقیماً از آن بخوانند.
معمولاً state را با useState نگه می داریم. اما وقتی چند لایه کامپوننت وسط راه هستند، رد کردن props خیلی خسته کننده می شود. اینجا Context و useContext به داد ما می رسند.
مشکل prop drilling در کامپوننت ها
پراب دریلیـنگ (Prop Drilling) یعنی یک prop را از کامپوننت بالا به پایین رد کنی، حتی به کامپوننت هایی که خودشان به آن داده نیاز ندارند.
مثل این است که دفتر حضور و غیاب را از مدیر به ناظم، بعد به معلم، بعد به نماینده کلاس بدهی؛ در حالی که فقط معلم و مدیر لازم دارند.
مثال: رد کردن props بین چند کامپوننت
import { useState } from "react";
import { createRoot } from "react-dom/client";
function Component1() {
const [user, setUser] = useState("Linus");
return (
<>
<h1>
{`Hello ${user}!`}
</h1>
<Component2 user={user} />
</>
);
}
function Component2({ user }) {
return (
<>
<h1>
Component 2
</h1>
<Component3 user={user} />
</>
);
}
function Component3({ user }) {
return (
<>
<h1>
Component 3
</h1>
<h2>
{`Hello ${user} again!`}
</h2>
</>
);
}
createRoot(document.getElementById("root")).render(
<Component1 />
);
اینجا Component2 فقط یک کار اضافی دارد: user را از بالا بگیرد و همان را به Component3 بدهد؛ خودش اصلاً از user استفاده نمی کند.
مدیریت داده با useContext در ری اکت
راه حل این مشکل این است که به جای رد کردن props در هر مرحله، یک کانتکست بسازیم و state را آنجا قرار بدهیم. بعد در هر کامپوننتی که خواستیم، مستقیم با useContext به آن دسترسی بگیریم.
گام 1: ساخت Context مشترک
اول باید createContext را import کنیم و یک context بسازیم. این کانتکست مثل یک «کانال مشترک» برای اطلاعات است.
import { useState, createContext, useContext } from "react";
import { createRoot } from "react-dom/client";
const UserContext = createContext();
گام 2: پیچیدن درخت با Provider
حالا باید کامپوننت هایی که به این داده نیاز دارند را داخل Provider قرار بدهیم. Provider یعنی «تأمین کننده» مقدار کانتکست.
function Component1() {
const [user, setUser] = useState("Linus");
return (
<UserContext.Provider value={user}>
<h1>
{`Hello ${user}!`}
</h1>
<Component2 />
</UserContext.Provider>
);
}
هر کامپوننتی که داخل UserContext.Provider باشد، می تواند مقدار user را بدون گرفتن props دریافت کند.
گام 3: خواندن مقدار با هوک useContext
حالا نوبت هوک useContext است. این هوک به کامپوننت می گوید از کدام کانتکست بخواند.
function Component3() {
const user = useContext(UserContext);
return (
<>
<h1>
Component 3
</h1>
<h2>
{`Hello ${user} again!`}
</h2>
</>
);
}
دیگر لازم نیست user از Component1 به Component2 و بعد به Component3 برسد. Component3 خودش مستقیم از UserContext مقدار می گیرد.
مسیر پیشنهادی یادگیری
- اول صفحه هوک useState را خوب بخوان.
- بعد صفحه هوک useEffect را مرور کن.
- حالا برگرد به این صفحه و تمرین useContext در ری اکت را انجام بده.
مثال کامل useContext در ری اکت
در این مثال کامل، دیگر هیچ propsی برای user رد نمی شود. همه چیز از UserContext می آید.
import { useState, createContext, useContext } from "react";
import { createRoot } from "react-dom/client";
const UserContext = createContext();
function Component1() {
const [user, setUser] = useState("Linus");
return (
<UserContext.Provider value={user}>
<h1>
{`Hello ${user}!`}
</h1>
<Component2 />
</UserContext.Provider>
);
}
function Component2() {
return (
<>
<h1>
Component 2
</h1>
<Component3 />
</>
);
}
function Component3() {
const user = useContext(UserContext);
return (
<>
<h1>
Component 3
</h1>
<h2>
{`Hello ${user} again!`}
</h2>
</>
);
}
createRoot(document.getElementById("root")).render(
<Component1 />
);
سعی کن اول خودت این مثال را در ادیتور بسازی، بعد کد را با مثال بالا مقایسه کن تا دقیقا متوجه شوی useContext در ری اکت چطور جلوی prop drilling را می گیرد.
اگر این صفحه را بعدا گم کردی، فقط در سایت UnderDevelops دنبالش بگرد و روی لینک useContext در ری اکت کلیک کن.
جمع بندی سریع
- ری اکت کانتکست برای مدیریت state به صورت سراسری استفاده می شود.
- useContext در ری اکت کمک می کند مستقیماً از کانتکست مقدار بگیری.
- با کانتکست دیگر نیازی به prop drilling خسته کننده نیست.
- Provider درخت کامپوننت ها را می پیچد و مقدار مشترک را می دهد.
- هر جا useContext را صدا بزنی، آخرین مقدار کانتکست را می گیری.