ایجاد UserContext
فرض کنید برای انتقال دادههای کاربر وارد شدهی به سیستم، از روش انتقال props از بالاترین کامپوننت موجود در component tree به پایینترین کامپوننت آن، نیاز است از Context استفاده کنیم. به همین جهت فایل جدید src\contexts\userContext.tsx را با محتوای زیر ایجاد میکنیم:
import React from "react"; export type User = { name: string; isActive: boolean; logOut: () => void; }; export const UserContext = React.createContext<User>({}); export const useUser = () => React.useContext(UserContext);
function React.createContext<User>(defaultValue: User, calculateChangedBits?: ((prev: User, next: User) => number) | undefined): React.Context<User>
Argument of type '{}' is not assignable to parameter of type 'User'. Type '{}' is missing the following properties from type 'User': name, isActive, logOutts(2345)
export const UserContext = React.createContext<Partial<User>>({});
نکته 1: البته میتوان آرگومان جنریک آنرا ذکر نکرد و createContext را با یک شیء آغازین از نوع User مقدار دهی کرد. در این حالت با استفاده از Type Inference، نوع آن، همان User درنظر گرفته میشود و دیگر نیازی به ذکر صریح این نوع نخواهد بود.
نکته 2: اگر از شیء مقدار دهی شدهی آغازین استفاده کنید، دیگر حتی نیازی به ذکر export type User هم نیست. نوع createContext بر اساس نوع خواص شیء آغازین ارسالی به آن در سراسر برنامه مشخص شده و قابل دسترسی میشود؛ با intellisense کامل و type checking دقیق.
نکته 3: useUser تعریف شده، در حقیقت یک هوک سفارشی است که میتوان بجای React.useContext از آن در سایر قسمتهای برنامه استفاده کرد.
نکته 4: اگر علاقمند به استفادهی از نوع Partial نیستید، میتوان از union types هم در اینجا استفاده کرد. در این حالت میتوان مقدار اولیه را undefined تعریف کرد:
export const UserContext = React.createContext<User | undefined>(undefined);
معرفی UserContext به بالاترین کامپوننت موجود در component tree
برای این منظور به فایل src\App.tsx مراجعه کرده و آنرا با UserContext.Provider محصور میکنیم:
import { User, UserContext } from "./contexts/userContext"; // ... function App() { const user: User = { name: "User 1", isActive: true, logOut: () => { console.log("LogOut."); }, }; return ( <UserContext.Provider value={user}> // ... </UserContext.Provider> ); } export default App;
خواندن شیء Context در کامپوننتی دیگر
برای این منظور به کامپوننت src\components\Head.tsx که در قسمتهای قبل ایجاد کردیم، مراجعه کرده و آنرا به صورت زیر تکمیل میکنیم:
import { UserContext } from "../contexts/userContext"; // ... export const Head = ({ title, isActive = true }: Props) => { const context = React.useContext(UserContext); // or useUser(); // ... };
اولین مزیت کار با TypeScript در اینجا، وجود intellisense کامل به همراه context است:
و یا اگر از Object Destructuring استفاده کنیم، در صورت وجود یک اشتباه تایپی، بلافاصله در زمان کامپایل، خطایی را دریافت میکنیم:
یک نکته: اگر UserContext را با استفاده از union types تعریف کنیم:
export const UserContext = React.createContext<User | undefined>(undefined);
علت اینجا است که با فعال بودن بررسی نوعهای نالنپذیر، چون user context اکنون میتواند undefined هم باشد، یا باید از روش context?.name استفاده کرد و یا یک علامت تعجب را پس از useContext قرار داد:
const context = React.useContext(UserContext)!; // or useUser()!; const { name } = context;