使用 useContext 管理全局状态
创建 Context,使用 Provider 包裹子树,并通过 useContext 使用其值,在无需逐层传递属性的情况下共享主题或身份验证状态。
使用 useContext 管理全局状态 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。
属性逐层传递的问题
属性逐层传递是指数据需要经过许多不使用它的中间组件,才能传递给深层嵌套的子组件。上下文通过让树中的任何组件都能访问某个值来解决这个问题,无需显式地逐层传递。
创建上下文
createContext(defaultValue) 会创建一个上下文对象。当组件读取上下文但上方没有匹配的提供者时,就会使用默认值。
import { createContext } from 'react';
interface ThemeContextType {
theme: 'light' | 'dark';
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
toggleTheme: () => {}
});提供上下文
用提供者包裹树中需要该上下文的部分。内部的所有组件都可以读取上下文值。
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const toggleTheme = () => setTheme(t => t === 'light' ? 'dark' : 'light');
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// In app root:
<ThemeProvider>
<App />
</ThemeProvider>使用 useContext 获取上下文
提供者内部的任何组件都可以通过 useContext(ThemeContext) 获取上下文值。无需将任何内容作为属性传递。
function ThemeToggle() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button onClick={toggleTheme}>
Switch to {theme === 'light' ? 'dark' : 'light'} mode
</button>
);
}使用自定义钩子封装 useContext
导出一个内部调用 useContext 的自定义钩子。这样比直接暴露上下文更简洁,还可以添加验证。
function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error('useTheme must be used inside ThemeProvider');
return ctx;
}
// Usage:
const { theme } = useTheme();上下文重新渲染
当提供者的值发生变化时,所有消费者都会重新渲染。如果该值是对象,那么每次渲染都创建新的对象引用会导致所有消费者重新渲染。请使用 useMemo 记忆化该值,以避免这种情况。
const value = useMemo(
() => ({ theme, toggleTheme }),
[theme] // toggleTheme is stable if created with useCallback
);
<ThemeContext.Provider value={value}>何时使用上下文
适合用于:主题、区域设置、已认证用户、功能开关、通知系统。不太适合用于:高频更新(每次按键都更新)、大型复杂状态(请改用状态管理库)。
多个上下文
您可以拥有多个相互独立的上下文。请让它们各司其职——使用 AuthContext 处理身份验证,使用 ThemeContext 处理主题。避免创建一个包含所有内容的万能上下文。
上下文与 Redux
上下文是内置功能,足以处理不经常变化的全局数据。Redux/Zustand/Pinia 更适合处理更新频繁的复杂状态、需要时间旅行调试或需要中间件的场景。
身份验证上下文模式
一种常见模式是:使用 AuthContext 保存当前用户和身份验证方法。使用该上下文的组件无需逐层传递属性即可获取用户信息。
interface AuthContext {
user: User | null;
login: (creds: Credentials) => Promise<void>;
logout: () => void;
}
const AuthCtx = createContext<AuthContext | null>(null);
export const useAuth = () => {
const ctx = useContext(AuthCtx);
if (!ctx) throw new Error('Outside AuthProvider');
return ctx;
};上下文与 TypeScript
使用接口为上下文声明类型。将 null 作为初始值,并在自定义钩子检测到该值为 null 时抛出错误。这样可以避免“在提供者外部使用上下文”这一不可能的状态被静默忽略。
性能:memo 与上下文
使用 React.memo 包装的组件只有在属性发生变化时才会重新渲染。如果上下文消费者的输出只依赖上下文的一部分,请拆分上下文或使用选择器模式,以避免不必要的重新渲染。
快速检查
在一个上方没有提供者的组件中调用 useContext(MyContext) 时,它会返回什么?
总结:useContext
createContext 会使用默认值创建上下文。使用提供者包装组件树,以提供一个值。在提供者内部的任何位置,都可以使用 useContext 读取该值。自定义钩子可以封装 useContext 以进行验证。请记忆化提供者的值,以避免不必要的重新渲染。它适合用于主题和身份验证等不经常变化的全局数据。
常见问题解答
「使用 useContext 管理全局状态」课时是免费的吗?
是的 — 「使用 useContext 管理全局状态」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。
「使用 useContext 管理全局状态」这节课中我会学到什么?
创建 Context,使用 Provider 包裹子树,并通过 useContext 使用其值,在无需逐层传递属性的情况下共享主题或身份验证状态。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Frontend Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 useContext 管理全局状态」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Frontend Academy 课中编写并运行代码吗?
能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 useContext 管理全局状态
- 使用 useReducer 管理复杂状态
- 使用 useMemo 与 useCallback 提升性能
- 自定义 Hook:提取可复用逻辑