React × Vue

React render 与 Vue setup

React 函数组件会随状态更新重新执行;Vue setup 通常只在组件创建时执行一次。

核心结论

React 函数组件本身就是一次 render:状态更新后,组件函数会重新执行并计算下一棵 UI。Vue 的 setup 更像组件实例的初始化入口,通常只执行一次,后续由响应式依赖触发模板更新。

不要把执行次数等同于 DOM 重建

React 重新执行组件函数,不代表整棵真实 DOM 都会重建;Vue 更新模板,也不代表完全不会重新运行组件的更新函数。两边最终都会比较并提交必要的 DOM 变化。

更新流程

组件关系与数据流

StateComponentRender / SetupHandler

差异焦点组件函数是 render 过程,不是只运行一次的初始化函数。

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

flowchart TB
  accTitle: React 函数组件重新执行模型
  accDescr: 事件调用 setter 后更新 state,React 调度一次新的 render,重新执行 ReactDemo 函数并生成下一棵 UI。
  event{{"点击事件"}} --> setter{{"调用 state setter"}}
  setter --> state(["count / compact state"])
  state --> schedule{{"调度新的 render"}}
  schedule --> demo["重新执行 ReactDemo"]
  demo -.->|"创建下一次事件处理函数"| event
  class state state
  class demo component
  class event,setter,schedule process
  classDef state fill:#fffdf8,stroke:#149eca,color:#25221d,stroke-width:1.2px
  classDef component fill:#e4f5fa,stroke:#149eca,color:#25221d,stroke-width:2px,font-weight:600
  classDef process fill:#f4fafb,stroke:#149eca,color:#25221d,stroke-width:1.6px
  classDef resource fill:#eee9df,stroke:#817a70,color:#25221d,stroke-width:1.4px

任意本地 state 更新都会调度 render,ReactDemo 函数从头再次执行。

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

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

组件关系与数据流

StateComponentRender / SetupHandler

差异焦点状态变化不会让 setup 从头执行,已有闭包和响应式引用继续复用。

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

flowchart TB
  accTitle: Vue setup 与响应式更新模型
  accDescr: setup 创建 refs 和事件函数一次,点击后直接修改 ref,响应式系统只调度读取该值的模板更新。
  setup{{"setup 创建一次"}} --> state(["count / compact refs"])
  setup --> handlers[("稳定的事件函数")]
  handlers -.->|"直接修改 ref"| state
  state --> trigger{{"触发响应式依赖"}}
  trigger --> template["更新相关模板节点"]
  class state state
  class template component
  class setup,trigger process
  class handlers resource
  classDef state fill:#fffdf8,stroke:#2f9d6b,color:#25221d,stroke-width:1.2px
  classDef component fill:#e4f4eb,stroke:#2f9d6b,color:#25221d,stroke-width:2px,font-weight:600
  classDef process fill:#f2f8f4,stroke:#2f9d6b,color:#25221d,stroke-width:1.6px
  classDef resource fill:#eee9df,stroke:#817a70,color:#25221d,stroke-width:1.4px

setup 保留 refs 和事件函数,状态变化后按响应式依赖更新模板。

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

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

完整 Demo 源码

以下代码直接读取在线 Demo 使用的源文件,没有省略或改写。

React 源码

ReactDemo.tsx
import { useRef, useState } from "react";export function ReactDemo() {  const executions = useRef(0);  const [count, setCount] = useState(0);  const [compact, setCompact] = useState(false);  executions.current += 1;  return (    <div className="demo-stack">      <div className="demo-card">        <span className="demo-tag">函数组件执行</span>        <h2>{compact ? "紧凑视图" : "标准视图"}</h2>        <p>count:{count}</p>        <p>ReactDemo 本次挂载已执行:{executions.current} 次</p>      </div>      <div className="demo-actions">        <button          className="demo-button"          type="button"          onClick={() => setCount((current) => current + 1)}        >          count + 1        </button>        <button          className="demo-button"          type="button"          onClick={() => setCompact((current) => !current)}        >          切换显示模式        </button>      </div>    </div>  );}

Vue 3 源码

VueDemo.vue
<script setup lang="ts">import { ref } from "vue";const setupExecutions = 1;const count = ref(0);const compact = ref(false);</script><template>  <div class="demo-stack">    <div class="demo-card">      <span class="demo-tag">setup 执行</span>      <h2>{{ compact ? "紧凑视图" : "标准视图" }}</h2>      <p>count:{{ count }}</p>      <p>VueDemo 本次挂载已执行 setup:{{ setupExecutions }} 次</p>    </div>    <div class="demo-actions">      <button class="demo-button" type="button" @click="count += 1">        count + 1      </button>      <button class="demo-button" type="button" @click="compact = !compact">        切换显示模式      </button>    </div>  </div></template>

在线观察

两个 Demo 都维护计数和显示模式,并记录逻辑执行次数。分别修改两个状态,观察 React render 次数与 Vue setup 次数。

React

函数组件执行

标准视图

count:0

ReactDemo 本次挂载已执行:1 次

Vue 3

setup 执行

标准视图

count:0

VueDemo 本次挂载已执行 setup:1 次

选择心智模型

问题ReactVue 3
组件逻辑何时运行每次 render 执行函数组件创建实例时执行 setup
状态如何推动更新setter 调度新的 renderref/reactive 触发依赖它的 effect
事件函数是否重建render 时重新创建通常由 setup 创建并复用

继续阅读响应式系统与状态更新模型理解“框架如何知道要更新”,再到状态 API学习日常写法。