客户端与服务端状态
客户端状态(表单输入、开关、主题)是同步、本地的;服务端状态(接口数据)是异步、远程的,会过期、需缓存与失效。两者用不同工具管理。
把服务端数据塞进 Redux/Pinia 会重复造缓存轮子。交给 React Query/SWR/TanStack Query 这类库更省心。
组件内状态
局部 UI 状态优先留在组件内(useState/ref)。只在该状态需要被多组件共享时再提升或外置。
const [open, setOpen] = useState(false); // 仅本组件用的状态Context 共享
React Context 适合低频共享(主题、登录用户)。高频变化的状态用 Context 会导致大范围重渲染,应慎用或拆分。
const ThemeCtx = createContext('light');
function App() {
return <ThemeCtx.Provider value="dark"><Child/></ThemeCtx.Provider>;
}Provider value 变化会使所有消费组件重渲染。用 useMemo 稳定 value,或拆成多个 Context 隔离变化。
Redux 模式
Redux 是集中式、可预测的客户端状态容器:state + action + reducer,配合 Redux Toolkit 大幅简化样板。
const counter = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: { inc: s => { s.value++; } }
});Pinia
Vue 的 Pinia 是响应式、类型友好的集中状态库,比 Vuex 更简洁:定义 store,组件里直接读写并自动更新。
export const useCart = defineStore('cart', {
state: () => ({ items: [] as string[] }),
actions: { add(i: string) { this.items.push(i); } }
});服务端状态
React Query/SWR 把"取数、缓存、失效、重试"封装好:自动去重请求、按 key 缓存、后台刷新,组件只声明"我要这个数据"。
const { data, isLoading } = useQuery({
queryKey: ['user', id],
queryFn: () => fetchUser(id)
});选型建议
小项目组件内状态 + Context 足够;跨页面共享的客户端状态用 Pinia/Redux;服务端数据交给 Query 类库。别过度引入。
| 场景 | 推荐 |
|---|---|
| 局部 UI | 组件内 state |
| 低频全局(主题/用户) | Context / store |
| 高频共享客户端状态 | Pinia / Redux |
| 接口数据 | React Query / SWR |
常见陷阱与 FAQ
不需要。局部状态全局化会增加耦合与重渲染范围。遵循"最小共享"原则,能局部就不提升。
Vue/Pinia 可直接改;Redux 必须用 action 触发 reducer 返回新状态,否则不可追踪、不触发更新。
尽量避免。用成熟 Query 库处理缓存、失效与竞态,比手写更稳、更少 bug。