Vue 组件的 Props 到底能不能改?

单向数据流

Vue 推崇单向数据流这个概念,也就是数据流向必须是从父到子。子组件想要修改数据必须 emit 一个事件,父组件接收到事件后,由父组件修改数据传回到子组件。

我在 stackblitz 写了个例子,使用版本为 Vue@3.4.5。可以看到在,props proxy 的外层 handler 是 ReadonlyReactiveHandler

于是当你想直接修改 props 的时候会被狠狠拦住,提示 VM383:1 [Vue warn] Set operation on key "msg" failed: target is readonly.

留个后门

也是上面的图,能看到在 ReadonlyReactiveHandler 底下的目标数据仍然是原来的响应式数据(就是同一个,===true),所以底层的数据仍然是可以改的,并且是符合正常响应式表现的

官方文档本身就有提到这种直接修改 props 里的对象或数组的行为,态度是不推荐,因为这么做会导致数据流混乱,造成数据不知道在哪被改了的情况。但是文档也有提到,如果父子组件本身就是设计得紧密耦合的话,直接改也不是不行。

虽然 readonly() 本来就可以把整个响应式对象设置为只读,不这么做的原因据文档说是考虑到会有性能问题,而且确实会有少数这样的需求。于是子组件直接修改 props 的后门就留下来了。

P.S. 回想起来好像以前也跟 Vuex 那种数据更新哲学有关,总之大家都习惯了单向数据流的设定。

直接改还是香

我常常遇到直接把一个对象传到 v-model 的情况,子组件会对 modelValue 对象做一些修改,例如其中一个字段修改会重置另一个字段。因为上面提到的,props 底层可以直接改,那么就是直接就改好了,再加个 emit 是不是有点多此一举。

即使是非对象值得情况,好像 Vue 本身就在纵容这个行为。v-modeldefineModel() 都在简化单向数据流麻烦的操作,也是只需要一个等号就把数据更新到父组件了。确实,在大多数情况我都根本不在乎他是不是单向数据流,此时此刻只想修改数据,仅此而已。

computed? readonly!

其实早在 Vue2 就在用"直接改 props"这个"feature",但是为什么直到现在才水这么一篇呢?直接原因其实是在工作中突然遇到了"明明是 props 的底层对象,却总是提示 readonly 的情况"。

一开始以为是可写 computed 导致内层只读,但测试了一下发现不是,computed 只是一个快照,里面的东西如果本来是响应式的,那么他就是响应式的,如果本来是普通对象,那便是普通对象,跟 props 一样 computed 也是只有最外层只读。

那如果 computed 本身不会让数据里层变成只读,那就只能说这个数据从来源上就已经是只读了......事实也是如此,那是从父组件的父组件传来的一个 useRequest 的数据,本身就不可改。

Vue 提供了 readonly(),可以把响应式数据限制为只读(并且深层也只读),不太常用,但在写 use 函数的时候可以用它提醒用户不能修改这个响应式数据,这个数据完全由 use 接管,所以写库的时候挺实用的。

最后回答标题,结论就是,只有 props 本身只读,内部对象保持原样。如果本来就是响应式数据,那么响应式特性依然存在,改了会更新页面......但文档上还是不推荐直接改。

相关链接

相关推荐
dy17171 小时前
element-plus表格默认展开有子的数据
前端·javascript·vue.js
2501_915918415 小时前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
程序员的世界你不懂5 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技5 小时前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
gnip6 小时前
JavaScript二叉树相关概念
前端
一朵梨花压海棠go6 小时前
html+js实现表格本地筛选
开发语言·javascript·html·ecmascript
attitude.x6 小时前
PyTorch 动态图的灵活性与实用技巧
前端·人工智能·深度学习
β添砖java7 小时前
CSS3核心技术
前端·css·css3
空山新雨(大队长)7 小时前
HTML第八课:HTML4和HTML5的区别
前端·html·html5