跳转到内容

Context 与 provide / inject

资料卡和操作面板没有直接传值关系,但它们都读取同一个用户上下文。修改用户名或角色时,两个消费者会同步更新。

React

Provider 传入 value,消费者通过 useContext 读取。

在线预览

Consumer A

小明

当前角色:访客

组件关系与数据流

StateComponentContext

差异焦点Provider 的 value 引用变化会推动 Context 消费者重新渲染。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: React Context Provider 更新机制
  accDescr: ReactDemo 每次渲染创建 Provider value 对象,value 身份变化后 useContext 消费者重新渲染,UserActions 通过 setUser 更新源状态。
  user(["user state"]) --> render{{"ReactDemo render 创建 value"}}
  render --> context[("UserContext.Provider value")]
  context --> profile["UserProfile useContext"]
  context --> actions["UserActions useContext"]
  actions -.->|"setUser"| user
  class user state
  class profile,actions component
  class render process
  class context resource
  classDef state fill:#ffffff,stroke:#149eca,color:#172033,stroke-width:1.2px
  classDef component fill:#e5f6fb,stroke:#149eca,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f4fbfd,stroke:#149eca,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

Provider value 身份随 render 更新,useContext 消费者接收新的上下文值。

React 流程图
React 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

实际运行源码

import { createContext, useContext, useState } from "react";
type User = {
name: string;
role: "访客" | "管理员";
};
type UserContextValue = {
user: User;
setName: (name: string) => void;
toggleRole: () => void;
};
const UserContext = createContext<UserContextValue | null>(null);
function useUser() {
const context = useContext(UserContext);
if (!context) throw new Error("Missing UserProvider");
return context;
}
function UserProfile() {
const { user } = useUser();
return (
<div className="demo-card">
<span className="demo-tag">Consumer A</span>
<h2>{user.name}</h2>
<p>当前角色:{user.role}</p>
</div>
);
}
function UserActions() {
const { user, setName, toggleRole } = useUser();
return (
<div className="demo-form">
<label className="demo-field">
Consumer B 修改用户名
<input
className="demo-input"
value={user.name}
onChange={(event) => setName(event.target.value)}
/>
</label>
<div className="demo-actions">
<button className="demo-button" type="button" onClick={toggleRole}>
切换角色
</button>
</div>
</div>
);
}
export function ReactDemo() {
const [user, setUser] = useState<User>({ name: "小明", role: "访客" });
const value: UserContextValue = {
user,
setName: (name) =>
setUser((current) => ({ ...current, name: name || "小明" })),
toggleRole: () =>
setUser((current) => ({
...current,
role: current.role === "访客" ? "管理员" : "访客",
})),
};
return (
<UserContext.Provider value={value}>
<div className="demo-stack">
<UserProfile />
<UserActions />
</div>
</UserContext.Provider>
);
}
Vue 3

祖先 provide,后代组件使用类型安全的 key inject。

在线预览

Consumer A

小明

当前角色:访客

组件关系与数据流

StateComponentContext

差异焦点共享的是响应式引用,不依赖 Provider value 的对象身份变化。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: Vue provide inject 响应式共享机制
  accDescr: setup 执行时 provide 一次包含 user ref 的上下文,inject 消费者读取同一个 ref,修改 ref 后只触发读取它的响应式视图更新。
  setup{{"setup 中 provide 一次"}} --> context[("userKey + user ref")]
  context --> profile["UserProfile inject"]
  context --> actions["UserActions inject"]
  actions -.->|"直接修改共享 ref"| user(["user ref"])
  user -->|"响应式依赖触发"| profile
  user --> actions
  class user state
  class profile,actions component
  class setup process
  class context resource
  classDef state fill:#ffffff,stroke:#42b883,color:#172033,stroke-width:1.2px
  classDef component fill:#e7f8f0,stroke:#42b883,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f2fbf7,stroke:#42b883,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

provide 传递同一个响应式 ref;inject 消费者按实际读取建立依赖。

Vue 3 流程图
Vue 3 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

实际运行源码

<script setup lang="ts">
import { provide, ref } from "vue";
import UserActions from "./UserActions.vue";
import UserProfile from "./UserProfile.vue";
import { userKey, type User } from "./userContext";
const user = ref<User>({ name: "小明", role: "访客" });
function setName(name: string) {
user.value.name = name || "小明";
}
function toggleRole() {
user.value.role = user.value.role === "访客" ? "管理员" : "访客";
}
provide(userKey, { user, setName, toggleRole });
</script>
<template>
<div class="demo-stack">
<UserProfile />
<UserActions />
</div>
</template>