Props是组件间传递数据的只读信使,父组件通过它向子组件传参,子组件不可修改;需注意字符串字面量不绑定、复杂类型须用v-bind、驼峰与短横线对应、类型校验及默认值函数返回等规范。

Props 是什么:组件间的“数据信使”
Props 是 Vue 或 React 中父组件向子组件传递数据的唯一官方通道。它不是变量,也不是状态,而是一组只读的输入参数——子组件可以读取、渲染、基于它做计算,但不能直接修改。一旦你试图 this.props.count = 5(React)或 this.$props.name = 'xxx'(Vue),框架会报错或静默忽略,这是设计使然,不是 bug。
基础传参:写对格式,少踩语法坑
传参看着简单,但格式错一点就失效:
- 字符串字面量不用 v-bind / { }:<MyButton text="确定"></MyButton> —— 这里 text 接收到的是字符串 "确定"
- 数字、布尔、对象、数组必须绑定:<MyList :items="[1,2,3]" :loading="true" :config="{ size: 'large' }"></MyList> —— 少了冒号(v-bind)就会当字符串传
- 驼峰 vs 短横线要对应:定义 props 用 myProp,模板中必须写成 my-prop(Vue);React 中 JSX 始终用 myProp
类型校验:别让 undefined 悄悄毁掉渲染
不设 type 的 props 就像没锁的门——任何值都能进来,运行时才爆错。Vue 和 React 都支持声明式校验:
- Vue(Options API):用 props: { visible: { type: Boolean, default: false } } 明确类型和默认值;required: true 强制传入,开发环境下报警告
-
React(TypeScript):用 interface 定义 Props 接口,函数组件签名加上 const Button: React.FC
;TS 编译期就能捕获 onClick 传了 string 而不是 function 的问题 - 关键细节:对象/数组的 default 必须是函数返回值(default: () => ({})),否则多个组件实例会共享同一引用
进阶控制:从响应性到深层校验
复杂场景下,基础校验不够用:
- 自定义 validator:比如限制 status 只能是 'idle' | 'loading' | 'success',用 validator: val => ['idle','loading','success'].includes(val) 实时拦截非法值
- 响应式解构需谨慎:Vue 3 的 const { count } = defineProps(...) 是只读代理,解构后 count 不再响应式;应改用 toRefs(props) 或直接访问 props.count
- 透传 props($attrs / {...props}):父组件未声明的属性会自动进入 $attrs(Vue)或 props(React),适合做“容器组件”,但要小心把 class/style 也透传过去导致样式冲突,可显式剔除:v-bind="{ ...$attrs, class: undefined }"
避坑清单:那些上线后才暴露的隐形雷
这些错误不会立刻报红,但会让组件行为诡异:
- 用 props 做内部状态:比如把 props.isOpen 直接拿来控制弹窗显示,结果父组件没同步更新 isOpen,子组件就卡死——正确做法是 emit 事件通知父组件,由父组件控制状态
- 在 setup / constructor 里直接用 props 初始化 ref:此时 props 可能还没注入,拿到的是 undefined;应改用 onBeforeMount + watch(Vue)或 useEffect + useState(React)延迟读取
- 函数 props 忘记 bind / useCallback:每次父组件重渲染都传新函数,导致子组件不必要的 rerender;Vue 中用 :on-click="handleClick" 默认绑定 this,React 中务必包裹 useCallback
健壮的组件不是靠运气,而是靠对 props 边界和生命周期的清晰认知。每一条校验、每一次透传、每一个默认值,都是在为协作和维护减负。

















