Typowanie kontekstu i Custom Hooks
Tworzenie typowanego kontekstu z wartościami domyślnymi oraz pisanie Custom Hooks z jawnymi typami zwracanymi.
Typowanie kontekstu i Custom Hooks to bezpłatna lekcja React Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej React Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs React Academy zawiera 4 lekcji w sumie.
Typowany kontekst z createContext
Do createContext należy przekazać typ kontekstu i wartość domyślną. Gdy kontekst ma być używany wewnątrz providera, jako wartość domyślną należy ustawić null i obsłużyć ten przypadek za pomocą warunku ochronnego.
interface AuthContextType {
user: User | null;
login: (credentials: Credentials) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | null>(null);Wzorzec hooka ochronnego
Należy utworzyć niestandardowy hook, który odczytuje kontekst i zgłasza wyjątek, jeśli zostanie użyty poza swoim providerem. Eliminuje to konieczność sprawdzania wartości null w każdym miejscu wywołania.
export function useAuth(): AuthContextType {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}Typowanie providera
Komponent provider opakowuje children i udostępnia wartość kontekstu. Należy jawnie określić typ obiektu wartości, aby TypeScript sprawdził jego zgodność z typem kontekstu.
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const login = async (creds: Credentials) => {
const u = await apiLogin(creds);
setUser(u);
};
const logout = () => setUser(null);
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}Kontekst z wartością domyślną
Jeśli istnieje sensowna wartość domyślna, na przykład motyw, należy przekazać ją bezpośrednio do createContext, aby kontekst nigdy nie miał wartości null i nie wymagał hooka ochronnego.
interface ThemeContextType { theme: 'light' | 'dark'; toggle: () => void; }
const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
toggle: () => {},
});
export const useTheme = () => useContext(ThemeContext);Typowanie wartości zwracanych przez niestandardowe hooki
Należy jawnie określić typ zwracany przez niestandardowe hooki albo pozwolić, aby TypeScript wywnioskował go automatycznie. Jawne typy pełnią funkcję dokumentacji i zapobiegają przypadkowym zmianom kształtu wartości.
interface UseCounterReturn {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
function useCounter(initial = 0): UseCounterReturn {
const [count, setCount] = useState(initial);
return {
count,
increment: () => setCount(c => c + 1),
decrement: () => setCount(c => c - 1),
reset: () => setCount(initial),
};
}Typy zwracane jako krotki
Hooki zwracające parę wartości, takie jak useState, używają krotek. Należy typować je za pomocą as const albo jawnego typu krotki, aby destrukturyzacja była poprawnie wywnioskowana.
function useToggle(initial = false): [boolean, () => void] {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue(v => !v), []);
return [value, toggle];
}
// Destructuring correctly infers types:
const [isOpen, toggleOpen] = useToggle();Generyczne niestandardowe hooki
Niestandardowe hooki również mogą być generyczne. Generyczny hook useLocalStorage przechowuje dowolny typ, który można serializować, zapewniając pełne bezpieczeństwo typów.
function useLocalStorage<T>(key: string, initialValue: T): [T, (val: T) => void] {
const [stored, setStored] = useState<T>(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch { return initialValue; }
});
const setValue = (val: T) => {
setStored(val);
localStorage.setItem(key, JSON.stringify(val));
};
return [stored, setValue];
}Typowanie useReducer
Należy zdefiniować typy akcji jako unie rozróżniane, a kształt stanu jako interfejs. TypeScript wymusi wtedy używanie poprawnych typów akcji w reducerze.
interface State { count: number; status: 'idle' | 'loading'; }
type Action =
| { type: 'INCREMENT' }
| { type: 'SET_STATUS'; payload: State['status'] };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'INCREMENT': return { ...state, count: state.count + 1 };
case 'SET_STATUS': return { ...state, status: action.payload };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0, status: 'idle' });Typowanie useCallback & useMemo
TypeScript wywnioskuje typy dla useCallback i useMemo na podstawie funkcji fabrykującej. Należy dodawać jawne typy tylko wtedy, gdy wnioskowanie typów zawiedzie.
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.value);
},
[onChange]
);
const sorted = useMemo(
() => [...items].sort((a, b) => a.name.localeCompare(b.name)),
[items]
); // inferred as typeof itemsWzorzec selektora kontekstu z typami
Typowany hook selektora przyjmuje funkcję selektora i zwraca tylko potrzebny fragment wartości, zachowując pełne wnioskowanie typów.
function useAuthSelector<T>(selector: (ctx: AuthContextType) => T): T {
const ctx = useAuth();
return selector(ctx);
}
// Usage — TypeScript infers User | null:
const user = useAuthSelector(ctx => ctx.user);Unikanie any w hookach
W niestandardowych hookach nigdy nie należy używać any. Należy używać generyków, typu unknown z warunkami ochronnymi typów albo konkretnych interfejsów, aby zachować spójność łańcucha typów.
// Bad:
function useFetch(url: string): { data: any; loading: boolean } { ... }
// Good:
function useFetch<T>(url: string): { data: T | null; loading: boolean } {
const [data, setData] = useState<T | null>(null);
// ...
return { data, loading };
}Szybkie sprawdzenie
Jaki jest cel wzorca hooka ochronnego podczas typowania kontekstu Reacta?
Podsumowanie
Należy typować kontekst za pomocą jawnego interfejsu i hooka sprawdzającego wartość null. Typy zwracane przez niestandardowe hooki należy określać za pomocą interfejsów lub typów krotek, używać generyków w hookach wielokrotnego użytku oraz typować useReducer za pomocą rozróżnianych unii akcji, aby wykrywać niepoprawne wywołania dispatch już podczas kompilacji.
Często zadawane pytania
Czy lekcja „Typowanie kontekstu i Custom Hooks” jest bezpłatna?
Tak — pełny tekst „Typowanie kontekstu i Custom Hooks” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu React Academy, przejdź na CoddyKit PRO. Kurs React Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Typowanie kontekstu i Custom Hooks”?
Tworzenie typowanego kontekstu z wartościami domyślnymi oraz pisanie Custom Hooks z jawnymi typami zwracanymi. Ćwiczysz React Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć React Academy?
Nie wymagamy żadnego doświadczenia. React Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Typowanie kontekstu i Custom Hooks”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji React Academy?
Tak. Każda lekcja React Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Typowanie propsów i typów zwracanych przez komponenty
- Typowanie zdarzeń i refów w TypeScript
- Komponenty generyczne i typy narzędziowe
- Typowanie kontekstu i Custom Hooks