Context and custom hooks
Share app-wide values without passing props, and reuse logic.
Context gives a value to every component below a provider, without passing props through each level. Use it for things many parts of the app need: the signed-in user, the language or the theme.
React (JSX)
import { createContext, useContext, useState } from "react";
const LanguageContext = createContext("en");
export function App() {
const [lang, setLang] = useState("en");
return (
<LanguageContext.Provider value={lang}>
<button onClick={() => setLang(lang === "en" ? "ta" : "en")}>Switch language</button>
<Greeting />
</LanguageContext.Provider>
);
}
function Greeting() {
const lang = useContext(LanguageContext);
return <h1>{lang === "ta" ? "வணக்கம்" : "Welcome"}</h1>;
}Changing a context value redraws every component that reads it. Keep fast-changing data, such as text being typed, out of context.
Custom hooks
A custom hook is a function whose name starts with use and that calls other hooks. It shares logic, not state: each component that calls it gets its own copy.
React (JSX)
import { useEffect, useState } from "react";
export function useFetch(url) {
const [data, setData] = useState(null);
const [error, setError] = useState("");
useEffect(() => {
let cancelled = false;
setData(null);
setError("");
fetch(url)
.then((r) => (r.ok ? r.json() : Promise.reject(new Error(`Error ${r.status}`))))
.then((d) => { if (!cancelled) setData(d); })
.catch((e) => { if (!cancelled) setError(e.message); });
return () => { cancelled = true; };
}, [url]);
return { data, error, loading: !data && !error };
}
export function Jobs() {
const { data, error, loading } = useFetch("/api/jobs");
if (loading) return <p>Loading…</p>;
if (error) return <p>{error}</p>;
return <ul>{data.map((j) => <li key={j.id}>{j.title}</li>)}</ul>;
}Jobs now reads like a description of the screen, and any other page can load data the same way in one line.