Vue父子组件状态同步的最佳方式

开发
平时我们在使用Vue开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面也要用,今天我们就来看看怎么优雅的解决这个问题吧!

 一般来说我们实现这个功能,只需要父组件通过 props 传递给子组件就好了,但是理想很丰满,现实很骨感,如果我们直接在子组件更改传进来的 props ,不出意外浏览器会给你一坨大红色的报错,因为在Vue中我们的数据流动是自上而下的,而子组件直接更改父组件传来的 props 则是自下而上的数据流动,这是Vue不允许的。

所以通常我们的解决办法是,父组件通过 props 传入状态给子组件,子组件通过 props 来初始化另外一个内部的状态,子组件每次更改状态之后都通知父组件,然后由父组件来更改自己的状态,其实就是 props on emit 的应用,接下来我们来上代码。

父组件 Father.vue

 

  1. <template> 
  2.  <div class="father"
  3.         <h1>父组件维护的状态:{{food}}</h1> 
  4.         <son :food="food" @update:food="f => food = f"></son> 
  5.     </div> 
  6. </template> 

子组件 Son.vue

 

  1. <template> 
  2.  <div class="son"
  3.         <h2>子组件中维护的状态:{{innerFood}}</h2> 
  4.         <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button> 
  5.     </div> 
  6. </template> 
  7. <script> 
  8.  export default { 
  9.         data () { 
  10.           return { 
  11.               innerFood: this.food 
  12.           }   
  13.         }, 
  14.         props: { 
  15.             food: String 
  16.         }, 
  17.         watch: { 
  18.             innerFood (nv) { 
  19.                 this.$emit("update:food",nv) 
  20.             } 
  21.         } 
  22.     } 
  23. </script> 

可以看到我们上述的写法,其实是维护了父子组件中的不同的两个状态,我们做的工作只是将这两个状态同步了,这种写法没有任何问题,其实对于子组件的部分我们也可以通过 computed 来实现,下面我们来看一看另一种子组件内维护同步状态的方法:

子组件 Son.vue 的另一种写法

 

  1. <template> 
  2.  <div class="son"
  3.         <h2>子组件中维护的状态:{{innerFood}}</h2> 
  4.         <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button> 
  5.     </div> 
  6. </template> 
  7. <script> 
  8.  export default { 
  9.         props: { 
  10.             food: String 
  11.         }, 
  12.         computed: { 
  13.             innerFood: { 
  14.                 get () { 
  15.                     return this.food 
  16.                 }, 
  17.                 set (nv) { 
  18.                     this.$emit("update:food",nv) 
  19.                 } 
  20.             } 
  21.         } 
  22.     } 
  23. </script> 

好了,两种写法我们都已经演示完毕,现在我们来优化一下父组件中的写法。

父组件中可以看到我们之前在上面绑定了一个 update:food 事件,并且使用箭头函数做了一个赋值,其实这里我们可以稍微优化一下,不要箭头函数直接赋值,因为我们触发的是自定义事件,而我们触发的时候给的第一个参数就是新值,我们可以直接通过 $event 拿到这个值,所以可以写成如下形式:

优化后的父组件

 

  1. <template> 
  2.  <div class="father"
  3.         <h1>父组件维护的状态:{{food}}</h1> 
  4.         <son :food="food" @update:food="food = $event"></son> 
  5.     </div> 
  6. </template> 

到这里你以为就结束了?其实我们还可以更近一步,只要满足我们以上的事件命名方式,我们实际上可以使用 sync 修饰符代替事件的绑定,也就是我们不用写事件绑定了,但是子组件内部的事件触发依然不能少,最终优化的结果如下:

 

  1. <template> 
  2.  <div class="father"
  3.         <h1>父组件维护的状态:{{food}}</h1> 
  4.         <son :food.sync="food"></son> 
  5.     </div> 
  6. </template> 

到此我们就真的完成了父子组件的同步,当然在子组件中维护一个状态不一定是必须的,如果我们只用父组件传给我们的 props 做展示,而子组件没有对这个 props 直接更改的行为,那么我们就不用在子组件创建另外一个状态,我们子组件想改他的时候只需要在合适的时机提交合适的事件即可,但是有一种情况我们不得不在子组件中创建另一个状态,就是我们父组件传入的状态在子组件中用于 v-model 这种双向数据绑定的功能时,由于 v-model 会自动更改值所以直接填入从父组件接受的 props 就不合适了。

 

 

责任编辑:姜华 来源: 晨曦大前端
相关推荐

2021-09-15 08:09:43

前端技术编程

2019-05-29 14:23:53

Vue.js组件通信

2023-04-18 09:17:40

父子组件Vue

2024-01-09 08:34:56

Vue3.js组件通信

2021-09-13 09:20:20

前端框架VUE

2022-07-27 08:40:06

父子组件VUE3

2022-05-06 08:47:10

Vue 3组件前端

2020-04-08 18:29:20

Vue组件属性

2024-10-15 07:42:09

Vue动态加载

2023-03-30 11:50:34

2019-04-10 08:24:06

vue组件通信

2019-08-14 10:00:08

vue组件通信前端

2017-02-28 21:57:05

React组件

2019-05-15 08:00:00

vue组件间通信前端

2015-11-03 08:12:44

2009-12-15 14:42:56

OSPF路由协议

2022-02-08 15:55:00

Vue组件库Vue Demi

2015-06-25 09:43:07

2022-03-11 12:31:04

Vue3组件前端

2021-12-29 07:09:43

React框架Vue
点赞
收藏

51CTO技术栈公众号