Explain in detail the best way to synchronize the state of vue parent and child components

  • 2021-08-12 02:02:27
  • OfStack

Hello! Hello, everyone! I am papaya too fragrant, A veteran front-end engineer, when we use vue for development, we may encounter the situation that a certain state of the parent component and the child component needs to be synchronized. Usually, this is because when we package the component, we have the same state to use outside and inside. Today, let's take a look at how to solve this problem gracefully.
1 Generally speaking, we realize this function, All you need to do is pass the parent component to the child component through props, However, the ideal is full, and the reality is very skinny. If we change the incoming props directly in the subcomponent, the browser will give you a big red error, because our data flow is top-down in vue, while the subcomponent directly changes the props from the parent component from bottom-up data flow, which is not allowed by vue.

Therefore, our usual solution is that the parent component passes in the state to the child component through props, and the child component initializes another internal state through props. After each change of state, the child component notifies the parent component, and then the parent component changes its own state, which is actually the application of props on emit. Next, let's write the code.

Parent component Father. vue


<template>
  <div class="father">
    <h1> The state maintained by the parent component: {{food}}</h1>
    <son :food="food" @update:food="f => food = f"></son>
  </div>
</template>

Subcomponent Son. vue


<template>
  <div class="son">
    <h2> Status maintained in subcomponents: {{innerFood}}</h2>
    <button @click="innerFood = '100 Jin beef '"> Click to change subcomponent status </button>
  </div>
</template>
<script>
  export default {
    data () {
     return {
       innerFood: this.food
     } 
    },
    props: {
      food: String
    },
    watch: {
      innerFood (nv) {
        this.$emit("update:food",nv)
      }
    }
  }
</script>

It can be seen that our above writing method actually maintains two different states in parent and child components. What we do is to synchronize these two states. There is no problem in this writing method. In fact, we can also realize the part of sub-components through computed. Let's take a look at the method of maintaining synchronous states in another sub-component:

Another writing method of subcomponent Son. vue


<template>
  <div class="son">
    <h2> Status maintained in subcomponents: {{innerFood}}</h2>
    <button @click="innerFood = '100 Jin beef '"> Click to change subcomponent status </button>
  </div>
</template>
<script>
  export default {
    props: {
      food: String
    },
    computed: {
      innerFood: {
        get () {
          return this.food
        },
        set (nv) {
          this.$emit("update:food",nv)
        }
      }
    }
  }
</script>

Ok, we have demonstrated both ways of writing. Now let's optimize the writing in the parent component under 1.

You can see in the parent component that we previously bound 1 update on it: food event, and use the arrow function to make an assignment. In fact, we can optimize it slightly here, instead of directly assigning the arrow function, because we trigger a custom event, and the first parameter we give when triggering is a new value. We can get this value directly through $event, so it can be written as follows:

Parent component after optimization


<template>
  <div class="father">
    <h1> The state maintained by the parent component: {{food}}</h1>
    <son :food="food" @update:food="food = $event"></son>
  </div>
</template>

You think it's over here? In fact, we can take one step closer. As long as we meet the above event naming methods, we can actually use sync modifier instead of event binding, that is, we don't have to write event binding, but the event triggering inside subcomponents is still indispensable. The final optimization results are as follows:


<template>
  <div class="father">
    <h1> The state maintained by the parent component: {{food}}</h1>
    <son :food.sync="food"></son>
  </div>
</template>

At this point, we have really completed the synchronization of parent and child components. Of course, it is necessary to maintain 1 state in subcomponents. If we only use the props passed to us by the parent component for demonstration, Subcomponents have no behavior to change directly to this props, Then we don't have to create another state in the subcomponent, When our subcomponent wants to change it, it only needs to submit the right event at the right time. However, there is one case where we have to create another state in the child component, that is, when the state passed in by our parent component is used in the child component for the bidirectional data binding function of v-model, it is not appropriate to directly fill in the props accepted from the parent component because v-model will automatically change the value.


Related articles: