简体   繁体   中英

What's the proper way to update props on a Vue component instance

I'm trying to figure out the best way to update propsData created on a component instance. Basically I have a signature wrapper page, and receive a bunch of html which is rendered using v-html . Then I'm creating a variable number of signature pad components within that rendered html. Since I don't know what the html is going to be, I'm forced (best I can tell) to create the components on the fly after mounting.

So I'm running the following on the parent mounted() :

    initializeSignaturePads() {

        const signatureAreas = document.querySelectorAll('.signature_area');

        // dynamically create a new vue instance for each signature pad and mount onto the respective .signature_area element
        // since the html is loaded via ajax, we don't know where to render this template on load, so a new Vue must be created
        signatureAreas.forEach(element => {
            const id = element.id;
            const signatureType = element.classList.contains('initials') ? 'initials' : 'signature';

            if (this.needsCustomerSignature(id)) {
                let length = this.signatures.push({
                    fieldName: id,
                    valid: false,
                    data: null,
                    type: signatureType
                });

                const SignaturePadClass = Vue.extend(SignaturePad);
                const SignaturePadInstance = new SignaturePadClass({
                    parent: this,
                    propsData: {
                        fieldName: id,
                        editable: true,
                        signatureType: signatureType,
                        signatureIndex: length - 1,
                        signatureData: null
                    }
                });

                // add handler for signed emit
                SignaturePadInstance.$on('signed', signature => {
                    this.padSigned(signature);
                });

                // watch this for an accepted signature, then pass to each child
                this.$watch('createdSignature.accepted', function (val) {
                    let signatureData = null;

                    if (val) {
                        signatureData = signatureType == 'signature' ? this.createdSignature.signatureData : this.createdSignature.initialsData;
                    }

                    // These two lines are the problem
                    SignaturePadInstance._props.signatureData = signatureData;
                    SignaturePadInstance._props.editable = !val;
                });

                SignaturePadInstance.$mount(element);
            }
        });
    },

As far as I can tell, that propsData is now statically set on the component. But for the signatureData and editable props, I need to be able to pass that to the child components when they're updated. The watcher is working correctly and the prop is getting updated, but I'm getting the Avoid mutating a prop directly warning. Which is understandable, since I'm directly mutating the prop on the child. Is there Is there a good way to handle this?

I was able to get this figured out, after I found this stackoverflow answer . When setting props on the propsData , I was using all primitive types, so they didn't have the built in reactive getters and setters. It makes sense now that I realize that, what I was doing was the equivalent of passing a string as a prop to an component element. After I did that, the prop was reactive and I didn't have to bother with manually creating watchers.

Anyways, this was the solution:

const SignaturePadInstance = new SignaturePadClass({
    parent: this,
    propsData: {
        fieldName: id, // << primitive
        editable: true, // << primitive
        signatureType: signatureType, // << primitive
        signatureIndex: length - 1,  // << primitive
        createdSignature: this.createdSignature  // << reactive object, updates to the child when changed
    }
});

I used Vue.observable (VueJS 2.6 and above) to make the property reactive. Here's a complete example:

    initializeSignaturePad() {
       const signaturePadComponent = Vue.extend(SignaturePad)
       this.instance = new signaturePadComponent()
       instance._props = Vue.observable({
          ...instance._props,
          editable: true
       })
       this.instance.$mount()
       document.body.appendChild(instance.$el)
    }
    
    onSignatureAccepted {
        this.instance.editable = false
    }
        

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM