background

Recently, the project needed to realize a large data page that switched by month and displayed multiple pieces of data and multiple operations, so we divided several sub-components according to data types for development.

The operation on the data in the market needs to use the currently selected month information, so we are going to pass the month information into the data sub-component. However, considering that some sub-components are relatively deep and do not want to write too much prop, we plan to use provide/ Inject for data interaction between components.

Initial use

Provide /inject binding data is not responsible and cannot directly pass a value, so we use the method of passing a function to return the month.

/ / the parent component
<template>
    <input type="month" id="myMonth" v-model="month">
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            month: 'the 2021-10'}; },provide() {
        return {
            getProvideMonth: this.getProvideMonth,
        };
    },

    methods: {
        getProvideMonth() {
            return this.month;
        },
    },
}
</scritp>

// Subcomponent Components /test.vue
<template>
    <span>Month: {{getProvideMonth()}}</span>
</template>

<script>
export default {
    inject: ['getProvideMonth']
}
</scritp>
Copy the code

The effect is that the child component can change as the month information in the parent component changes.

further

Listen to object

The official documentation describes it as follows,

If you pass in a listening object, the object’s property is still responsive.

So, the first thing I want to do is declare an object in data to implement the month’s responsive logic.

/ / the parent component
<template>
    <input type="month" id="myMonth" v-model="monthObj.value">
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            monthObj: {
                value: 'the 2021-10',}}; },provide() {
        return {
            monthObj: this.monthObj,
        };
    },
}
</scritp>

// Subcomponent Components /test.vue
<template>
    <div>
        <div>monthObj:{{ monthObj.value }}</div>
    </div>
</template>

<script>
export default {
    inject: ['monthObj']
}
</scritp>
Copy the code

Here we place the information for Month in the responsive object monthObj so that its data can be retrieved from the changed value in the child component.

Reference to an immutable listener

One thing to note here is that the reactive object needs to be a listener with a constant reference. Then, a reactionable failure occurs in one of the following situations.

  • Use computed to return objects
/ / the parent component
<template>
    <mtd-date-picker type="month" placeholder="Choose the time" value-format="yyyy-MM" v-model="month" />
    <div>MonthObj :{{monthObj. Value}}</div>
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            month: 'the 2021-10'}; },computed: {
        monthObj() {
            return {
                value: this.month, }; }},provide() {
        return {
            monthObj: this.monthObj,
        };
    },
}
</scritp>

// Subcomponent Components /test.vue
<template>
    <div>
        <div>monthObj:{{ monthObj.value }}</div>
    </div>
</template>

<script>
export default {
    inject: ['monthObj']
}
</scritp>
Copy the code

  • Give it an objectmonthObjThe assignment
/ / the parent component
<template>
    <mtd-date-picker type="month" placeholder="Choose the time" value-format="yyyy-MM" v-model="month" />
    <div>MonthObj :{{monthObj. Value}}</div>
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            month: 'the 2021-10'.monthObj: {
                value: 'the 2021-10',}}; },watch: {
        month() {
            this.monthObj = { value: this.month }; }},provide() {
        return {
            monthObj: this.monthObj,
        };
    },
}
</scritp>

// Subcomponent Components /test.vue
<template>
    <div>
        <div>monthObj:{{ monthObj.value }}</div>
    </div>
</template>

<script>
export default {
    inject: ['monthObj']
}
</scritp>
Copy the code

The final solution

In the example above, we are passing one parameter, but it is possible to pass multiple parameters, and multiple parameters result in maintenance for multiple corresponding functions or objects. In order to leave work early, we can pass this directly as the responsible object here.

/ / the parent component
<template>
    <mtd-date-picker type="month" placeholder="Choose the time" value-format="yyyy-MM" v-model="month" />
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            month: 'the 2021-10'}; },provide() {
        return {
            app: this}; }, } </scritp>// Subcomponent Components /test.vue
<template>
    <div>
        <div>Subcomponent app:{{app.month}}</div>
    </div>
</template>

<script>
export default {
    inject: ['app']
}
</scritp>
Copy the code

Of course, sometimes we don’t want to expose all the attributes of the parent component to the child component, so we can add a function that returns all the attributes that need to be exposed to the child component (the method that the current project ends up using).

/ / the parent component
<template>
    <mtd-date-picker type="month" placeholder="Choose the time" value-format="yyyy-MM" v-model="month" />
    <Test />
</template>

<script>
import Test from './components/test.vue';

export default {
    components: { Test },
    
    data() {
        return {
            month: 'the 2021-10'}; },provide() {
        return {
            getApp: this.getApp,
        };
    },
    
    methods: {
        getApp() {
            return {
                month: this.month,
                // Other attributes to expose
            };
        },
    },
}
</scritp>

// Subcomponent Components /test.vue
<template>
    <div>
        <div>Subcomponent app:{{getApp().month}}</div>
    </div>
</template>

<script>
export default {
    inject: ['getApp']
}
</scritp>
Copy the code

conclusion

The data bound in provide/inject is not responsible. To implement the response, a listener object needs to be passed and the application of the object cannot change.

The resources

  • New vUE features provide/ Inject In-depth study