跳转到内容

useState 与 ref / reactive

两个计数器维护相同的数字和对象状态。操作结果一致,更新状态时的写法与心智模型不同。

React

调用 setter 并创建新的对象状态。

在线预览

useState

小明的计数器

count:0

score:0

组件关系与数据流

StateComponentAction

差异焦点状态更新依赖 setter,组件函数会再次执行。

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

flowchart TB
  accTitle: React useState 调度渲染
  accDescr: 点击事件调用 setter 并创建新的状态值,React 将更新加入调度队列,随后重新执行 ReactDemo 函数组件并生成 UI。
  event{{"button event"}} --> setter{{"setter 创建新值"}}
  setter --> state(["count + profile state"])
  state --> schedule{{"调度重新渲染"}}
  schedule --> demo["重新执行 ReactDemo"]
  demo -.->|"下一次点击"| event
  class state state
  class demo component
  class event,setter,schedule process
  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

setter 提交新状态后,React 调度并重新执行整个函数组件。

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

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

实际运行源码

import { useState } from "react";
type Profile = {
name: string;
score: number;
};
export function ReactDemo() {
const [count, setCount] = useState(0);
const [profile, setProfile] = useState<Profile>({
name: "小明",
score: 0,
});
function increment() {
setCount((current) => current + 1);
setProfile((current) => ({
...current,
score: current.score + 1,
}));
}
function reset() {
setCount(0);
setProfile((current) => ({ ...current, score: 0 }));
}
return (
<div className="demo-stack">
<div className="demo-card">
<span className="demo-tag">useState</span>
<h2>{profile.name}的计数器</h2>
<p>count:{count}</p>
<p>score:{profile.score}</p>
</div>
<div className="demo-actions">
<button className="demo-button" type="button" onClick={increment}>
同时加一
</button>
<button className="demo-button" type="button" onClick={reset}>
重置
</button>
</div>
</div>
);
}
Vue 3

修改 ref.value 或 reactive 对象属性。

在线预览

ref / reactive

小明的计数器

count:0

score:0

组件关系与数据流

StateComponentAction

差异焦点setup 不会因状态变化整体重跑,响应式依赖负责定向更新。

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

flowchart TB
  accTitle: Vue 响应式依赖触发更新
  accDescr: 点击事件直接修改 ref 和 reactive,响应式系统通知读取这些属性的模板依赖,只重新执行相关渲染更新。
  event{{"button event"}} --> mutate{{"直接修改 .value / 属性"}}
  mutate --> state(["count ref + profile reactive"])
  state --> trigger{{"触发已收集的响应式依赖"}}
  trigger --> demo["更新相关模板节点"]
  demo -.->|"下一次点击"| event
  class state state
  class demo component
  class event,mutate,trigger process
  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

直接修改响应式值后,Vue 根据依赖关系更新相关模板节点。

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

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

实际运行源码

<script setup lang="ts">
import { reactive, ref } from "vue";
const count = ref(0);
const profile = reactive({
name: "小明",
score: 0,
});
function increment() {
count.value += 1;
profile.score += 1;
}
function reset() {
count.value = 0;
profile.score = 0;
}
</script>
<template>
<div class="demo-stack">
<div class="demo-card">
<span class="demo-tag">ref / reactive</span>
<h2>{{ profile.name }}的计数器</h2>
<p>count:{{ count }}</p>
<p>score:{{ profile.score }}</p>
</div>
<div class="demo-actions">
<button class="demo-button" type="button" @click="increment">
同时加一
</button>
<button class="demo-button" type="button" @click="reset">重置</button>
</div>
</div>
</template>