🎙 欢迎来到《前端达人 · 播客书单》第 26 期。
本期我们将聚焦 React 应用中最常见但也最容易误用的机制:Context API。 你可能早就知道它能“解决 props drilling”,但它到底该怎么用?用在哪儿最合理?项目中真的能撑起状态管理吗?
今天我们不讲概念,而是用一个完整业务场景来串讲:
登录状态管理 + 权限控制 + 页面加载指示
想象你开发一个中后台管理系统,有如下需求:
这时候你该怎么做?
如果你还在层层 props 传递,或者每个组件都重新调用 API 获取用户数据…… ❌ 你的状态架构可能存在问题!
我们用一句话定义「共享状态」:
跨越多个组件层级,且多个组件都要“读取或依赖”的状态
在本项目中,有三类典型共享状态:
状态类型 | 示例字段 | 使用位置 |
---|---|---|
用户信息 | user.name, user.role | Header / Sidebar / ProtectedRoute |
权限数组 | permissions: string[] | Sidebar 菜单 / 页面权限判断 |
全局状态 | loading, dispatch() | 按钮、跳转、加载框等全局控制点 |
我们来实现一个可复用的 AppContext
,管理上面提到的状态 👇
type State = {
user: { id: string; name: string } | null;
permissions: string[];
loading: boolean;
};
type Action =
| { type: "login"; user: State["user"] }
| { type: "set_permissions"; permissions: string[] }
| { type: "set_loading"; loading: boolean };
function reducer(state: State, action: Action): State {
switch (action.type) {
case"login":
return { ...state, user: action.user };
case"set_permissions":
return { ...state, permissions: action.permissions };
case"set_loading":
return { ...state, loading: action.loading };
default:
return state;
}
}
const AppContext = createContext<{
state: State;
dispatch: React.Dispatch<Action>;
} | null>(null);
exportfunction AppProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(reducer, {
user: null,
permissions: [],
loading: false,
});
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
}
const Header = () => {
const { state } = useContext(AppContext);
return <div>👋 Welcome, {state.user?.name ?? "Guest"}</div>;
};
const Sidebar = () => {
const { state } = useContext(AppContext);
const menu = state.permissions.includes("admin")
? ["Dashboard", "User Management"]
: ["Dashboard"];
return <Menu items={menu} />;
};
const LoginButton = () => {
const { dispatch } = useContext(AppContext);
const handleLogin = async () => {
dispatch({ type: "set_loading", loading: true });
const user = await fakeLoginAPI();
dispatch({ type: "login", user });
const perms = await fetchUserPermissions(user.id);
dispatch({ type: "set_permissions", permissions: perms });
dispatch({ type: "set_loading", loading: false });
};
return <button onClick={handleLogin}>登录</button>;
};
export function useAppContext() {
const ctx = useContext(AppContext);
if (!ctx) throw new Error("Context 未初始化!");
return ctx;
}
#React #React播客 #前端播客 #前端达人 #TypeScript