Through reading official documents and a large number of netizens’ blog posts, I integrated my own ideas, sorted out my views on component communication, and posted a document for the first time. Please forgive me if there is something wrong

The reason for communication between components

Component instances are isolated in scope, but relationships and interactions between components are unavoidable. Component communication is essential when components interact with each other.

The type of component communication

Thus, component communication can be divided into two cases:

Communication between parent and child components (parent to child, child to parent), communication between non-parent components.




Parent to child type



Prop the value



Step1: the parent component passes properties with prop custom properties, which have literal and dynamic syntax. Literals can only pass data as strings; Dynamic syntax is similar to V-bind in that it can pass real-time changes in parent component data to child components.







Step2: The child component needs props to explicitly declare a prop. Subcomponent props can be written in two ways:

  • Array form:



  • Object form: Can be conditional



Child the parent

1. Callback parameter transmission

  1. The parent passes the function to the child using prop, and when the child calls the function, it passes the data as an argument to the parent

    Parent component:


    <child2 :changeParent="changeMyself"></child2>Copy the code

    methods: {
        // How the parent component changes its own data
        changeMyself (chidData) {
            this.parentChangeData = chidData
        }
    }Copy the code

    In child components:





    export default {
      // The child component displays functions that declare the props parent component
      props: {
        changeParent: {
          requried: true.// Indicates whether the message is mandatory
          type: Function // represents the data type
        }
      },
      data () {
        return {
          childData: 'I'm going to pass this data to the parent.'}}}Copy the code

    <button @click="changeParent(childData)">Click I pass the data to the parent component</button>Copy the code

2. Customize events + event listening

The child $emit defines a custom event with the event name as the first argument and the data as the second argument. The parent V-ON binds an event listener to get the child component’s data in the form of parameters in the method binding.

In child components:

methods: {
    // Custom event $emit exposes data as an argument
    changeParent () {
      this.$emit('change'.this.childData)
    }
}Copy the code

Parent component:

<! -- Parent component binding listener, get child component data -->
<child3 @change="changeMyself"></child3>Copy the code

methods: {
    // How the parent component changes its own data
    changeMyself (chidData) {
        this.parentChangeData = chidData
    }
}Copy the code

3. Direct access

The child is marked with ref, and the parent gets the child’s data directly through this.$refs[child ref].[Child attribute/method].

Note: “$refs is filled only after the component has rendered, and it is non-responsive. It is only intended as a contingency plan for direct access to child components — use of $refs in templates or computed properties should be avoided. The official website says so, just for emergency use, generally not recommended

Consider: single data flow

Prop is unidirectional: when a property of the parent component changes, it passes to the child component, but not vice versa. This is to prevent the child component from inadvertently modifying the state of the parent component to prevent the data flow of the application from becoming difficult to understand.

In addition, every time the parent component is updated, all prop of the child component is updated to the latest value. This means that you should not change prop inside child components. If you do, Vue will warn you on the console.

There are two situations where it is tempting to modify data in prop:

  1. When Prop is passed in as an initial value, the child component wants to use it as local data.

  2. Prop is passed in as raw data and processed by child components into other data output.

In both cases, the correct response is:

  1. Define a local variable and initialize it with the value of prop:



  2. Define a calculation property that handles the value of prop and returns:



Consider: bidirectional binding of child and parent

A single data flow prevents a child component from directly modifying the parent component’s data. In the real world, however, there are many times when you need to change the parent’s data in the child component.

Methods:

  1. The parent has a method that changes its own data, passed to the child with prop, which is called when it needs to change the parent’s data. (Consistent with the callback parameter method)

  2. The child component sends the data through an event, and the $emit event passes the data to the parent component, which listens and performs its own methods to change its data. (Consistent with the second method of passing from son to father)

  3. The parent component has a method that changes its own data. The child calls the parent method directly through this.$parent

    1. Parent component:

      methods: {
          // How the parent component changes its own data
          changeMyself (chidData) {
              this.parentChangeData = chidData
          }
      }Copy the code

      In child components:

      export default {
        data () {
          return {
            childData: 'I am the data that the son passes to the father.'}},methods: {
          change () {
            // Through a direct access method call
            this.$parent.changeMyself(this.childData)
          }
        }
      }Copy the code

    However, the above methods are event-based and cannot ensure that the data of the child and parent components are synchronized at all times

    4. Use the.sync binding modifier to highlight bidirectional binding in the parent component prop. The child uses $emit(‘ update:data ‘,newVal) on watch to update the data sent by the parent prop. The parent does not need to listen for the update method.



    Parent component:

    <! Sync modifier -->
    <child6 :parentData.sync= "parentData"></child6>Copy the code

    In child components:

    props: ['parentData']Copy the code

    // The child listens for data
    watch: {
        childData (newVal, oldVal) {
          this.$emit('update:parentData', newVal)
        }
    }Copy the code

The custom event here is a little different from the custom event passed from child to parent.

<child6 :parentData.sync="parentData"></child6>

Will be extended to:

<child6 :parentData"parentData" @update:parentData="val => parentData = val"></child6>

Think about:

The response expression to run when a custom event occurs is
parentData= val”> “val => bar = val “.

In the “send data from child to parent via $emit event”, the response expression to run when a custom event occurs is: < child-@chang =”changeMyself”> changeMyself in .

In the former case, the expression val => bar = val means that the parent component’s data is forced to be equal to the data passed by the child, and in this case, we find that the parent and child components are equal. The parent can change the child (data) and the child can change the parent (data).

For the latter, changeMyself is defined in the parent component. In this function, you can do whatever you want with the data received from the child. The parent can change the child, but the child cannot change the parent directly! Changes to the data in the parent can only be determined by the parent itself.

There is a way to cut corners: If the props type is object or array, you can modify the props data in the child component without error detection. This makes data flow more difficult to analyze. In addition, if the props type is reference, Care should be taken to make deep copies of objects in child components to prevent implicit modification of objects in parent components.



Brother begets brother

1. Two sibling components have a common parent

Parent component:

<! The parent component passes the method of changing data to child2 and the data to Child, raising the data communication level to the parent component.
<child2 :changeParent="changeMyself"></child2>
<child :parent="parentChangeData"></child>Copy the code

Child2:

<! -- Child component calls method, taking data as argument -->
<button @click="changeParent(childData)">Click I pass the data to the parent component</button>Copy the code

export default {
  // The child component displays functions that declare the props parent component
  props: {
    changeParent: {
      requried: true.// Indicates whether the message is mandatory
      type: Function // represents the data type
    }
  },
  data () {
    return {
      childData: 'I'm going to pass this data to the parent.'}}}Copy the code

Child:

// Displays data for the props parent
props: {
    parent: {
      requried: true.// Indicates whether the message is mandatory
      type: String.// represents the data type
      default: 'I'm the default.'}}Copy the code

2. Route parameters are transmitted

Put the data that needs to be passed across the page after the URL, and get the URL string for the desired parameters when jumping to another page.

{
    path: '/params/:id'
    name: ' '.component: Sample
}Copy the code

<router-link :to="params/12">Hop routing</router-link>Copy the code

$route.params.id = 12, but this is only suitable for passing small data, such as numbers.

3.EventBus

First create a central time bus and introduce it into the components that need to be used. $emit(‘eventName’, value) with this.bus.$ON (‘eventName’, value => {this.print(value)}) Before $emit, you must already have $ON, so it is common to do $ON in a Created hook.



// Create a new bus.js file
import Vue from 'vue'
export default new Vue()Copy the code

Component A transmits data:

<script>
// Reference it in the component you want to use
import Bus from '@/components/Bus'
export default {
  data () {
    return {
      childData: 'I'm brother A, put my data into eventBus'}},methods: {
    submit () {
      // Trigger the event
      Bus.$emit('change'.this.childData)
    }
  }
}
</script>Copy the code

Component B receives data:

get () {
  // Listen for receive events
  Bus.$on('change', value => {
    this.myData = value
  })
}Copy the code

// Unbind the component when it is destroyed
destroyed () {
    Bus.$off('change')}Copy the code


Communication between components can be achieved using EventBus, regardless of the number of components, as long as the eventName is different. It is clearer and more manageable to have an empty Bus instance as the central EventBus instead of directly accessing root.

Special eventBus

Traditional eventBus is only responsible for $EMIT and $ON and has no interaction with data. This makes the data not “persistent”, only valid after $emit, and the same component generates more than one $ON. When switching routes, the binding of the new component and the unbinding of the old component need to be considered.

$on = Bus; $on = Bus;

// Create a new bus.js file
// The Bus listens and puts the data directly into the Bus
import Vue from 'vue'
const Bus = new Vue({
  data () {
    return {
      child7Val: ' '
    }
  },
  created () {
    this.$on('change', value => {
      this.child7Val = value
    })
  }
})
export default BusCopy the code


The component that emits data does not change

<script>
// Reference it in the component you want to use
import Bus from '@/components/Bus'
export default {
  data () {
    return {
      childData: 'I'm brother A, put my data into eventBus'}},methods: {
    submit () {
      // Trigger the event
      Bus.$emit('change'.this.childData)
    }
  }
}
</script>Copy the code


The component that receives the data is modified to access the data directly from the Bus using computational properties, which are used to keep the data dynamic.

computed: {
    child7Val () {
      return Bus.child7Val
    }
 }Copy the code


Vuex

My understanding is that Vuex is a large repository dedicated to storing shared variables.

After Vuex is installed, create the store.js file

import Vue from 'vue'
import Vuex from 'vuex'

import app from './modules/app'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    // Store shared variables
    msg: 'I'm raw data.'
  },
  getter: {
    // Corresponds to the computed properties in store
    mymsg: state= > {
      return state.msg
    }
  },
  mutations: {
    // Change state,vue recommends using uppercase
    MUTATIONSMSG (state, payload) {
      state.msg = payload.msg
    }
  },
  actions: {
    // Similar to mutations, asynchronous is supported
    mutationsMsg (context, payload) {
      context.commit('MUTATIONSMSG', payload)
    }
  },
  modules: {
    app
  },
  strict: process.env.NODE_ENV ! = ='production'
})

export default storeCopy the code

When using mutations to modify state:

Component A uses data from the Store:

<template>
  <div class="child">
    <h3>Component A</h3>
    {{$store.state.msg}}
  </div>
</template>Copy the code

Component B modifies the data in store:

<script>
export default {
  data () {
    return {
      myData: 'Data for Component B'}},methods: {
    get () {
      this.$store.commit('MUTATIONSMSG'.this.myData)
    }
  }
}
</script>Copy the code

When changing state using Actions:

<script>
export default {
  data () {
    return {
      myData: 'Data for Component B'}},methods: {
    get () {
      this.$store.dispatch('mutationsMsg'.this.myData)
    }
  }
}
</script>Copy the code

State is used to store shared variables. This.$store.state.[variable] is used to obtain shared variables.

Getter, which can add a getter derived state (equivalent to a computed property in store), store.getters. The method name () is used to get the value of the shared variable.

Mutations are used to store the method for changing state.

Actions is also used to store methods for changing state, but action is based on mutations. Commit mutations method in Actions first, and dispatch by using the Actions component


thinking

  • The idea of componentization is to keep components independent and data independent

  • Modifying the value of component B directly through component A, such as bidirectional binding, is convenient but increases the coupling between components. The best thing to do is if component A changes the value of component B, expose the modified data, and let component B get the data and modify it.