单向数据流是必须遵守的约束规则:父组件通过props向下传值,子组件不可直接修改props,否则触发警告且修改无效;正确做法是将props作为只读输入,通过data声明本地状态或computed+setter配合$emit通知父组件更新。

单向数据流不是“用法”,而是必须遵守的约束规则:父组件通过 props 往下传数据,子组件绝不能直接改 props 的值——改了也不会生效,还会触发控制台警告。
为什么子组件改 props 会报 warning?
Vue 和 React 都会在开发模式下检测对 props 的直接赋值,并抛出类似这样的警告:[Vue warn]: Avoid mutating a prop directly 或 React 的 Cannot assign to read only property。这不是 bug,是框架在拦截违反单向流的行为。
根本原因是:props 是只读快照,每次父组件重渲染,子组件的 props 都会被重新覆盖。你刚赋的值,下一帧就被冲掉了。
- 即使看起来“改成功了”(比如界面短暂变化),也是因为你操作的是本地引用或 DOM,不是真实响应式更新
- 一旦父组件触发更新(比如父级
data变了),你的修改立刻消失 - 调试时你会看到状态“跳变”,很难定位源头
子组件想改数据,正确姿势是什么?
核心原则:把 props 当作输入,而不是可写变量。需要“可变副本”时,必须显式声明为本地状态。
立即学习“前端免费学习笔记(深入)”;
- 用
data()初始化一个新变量,初始值取自props:return { localCount: this.count } - 用
computed+setter封装双向逻辑(适合简单场景):computed: { count: { get() { return this.localCount }, set(val) { this.$emit('update:count', val) } } } - 配合
.sync或v-model语法糖,本质仍是$emit通知父组件更新
例如父组件传 :count.sync="total",子组件内部只需 this.$emit('update:count', newValue),Vue 自动帮你映射成 total = newValue。
v-model 在组件中怎么适配单向流?
v-model 不是魔法,它只是语法糖。在自定义组件上使用时,等价于同时绑定 :value 和监听 @input(Vue 2)或 :modelValue + @update:modelValue(Vue 3)。
所以子组件要支持 v-model,必须:
- 声明
props: ['modelValue'](Vue 3)或props: ['value'](Vue 2) - 触发更新时用
this.$emit('update:modelValue', newVal)或this.$emit('input', newVal) - 模板里绑定
:value="modelValue"而不是:value="props.value"(避免重复绑定)
漏掉任一环,v-model 就失效——常见错误是只接收 value 却没发 input 事件,或者发了事件但没按约定命名。
真正容易被忽略的点在于:单向流不是性能优化技巧,而是数据所有权的契约。哪怕你用 Object.assign 深拷贝 props 对象,只要没通过 $emit 或回调通知父级,这个数据就脱离了应用的响应式闭环——它成了孤岛。



















