Using Vue JS to handle image upload with "PROP MUTATING"

Apologies for any language barriers or inaccuracies in my English.

I have a single component designed specifically for image uploads. It is currently being utilized in two forms: an add form and an edit form. In the edit modal, the Image URL is passed as a prop like so:

<ua-single-upload :propsImage="editSingleImage" @uploadImage="addSingleImage = $event"></ua-single-upload>

The functionality is working well, displaying the image as expected:

https://i.sstatic.net/0pwAO.png

However, upon attempting to reload a new photo, an error message appears stating: "[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "propsImage""

https://i.sstatic.net/5YWvc.jpg

Furthermore...

The component fails to function properly with the ADD FORM. Upon selecting an image, it does not show or upload... I am seeking assistance from fellow developers.

My goal is to have a component that allows both adding a new image and updating an existing one.

Below are the codes for my Component:


<template>
   <div class="singleImageUpdate p-4">
      <div class="p-4">
         <h4>Select Cover Photo</h4>
      </div>
      <div class="p-4">
         <input 
            type="file"
            name="fileUrl" 
            id="file" 
            ref="fileInput" 
            @change="onFileChange" />

          <label for="file">Add New Photo</label>

          <button
            class="ml-4"
            type="button"
            v-if="this.propsImage != null"
            @click="onFileDelete"> Remove Photo </button>


          <button
           class="ml-4"
           type="button"
           v-else 
           disabled 
           @click="onFileDelete"> Remove Photo </button>
        </div>

        <div class="p-4 mt-4">
          <small v-if="this.propsImage">
              The photo has not been cropped, it is for representation purposes only.
          </small>
          <img 
             class="mt-4 shadow-lg"
             v-if="this.propsImage" 
             :src="propsImage" />
        </div>
      </div>
</template>

<script>
  export default{
    data(){
      return{}
    },
    props: {
      propsImage: String
    },
    methods: {
          onFileChange(event) {
            const file = event.target.files[0];
            this.propsImage = URL.createObjectURL(file);
            this.$emit("updateSingleImage", 1);
            this.$emit("uploadImage",event.target.files[0]);
          },
          onFileDelete() {
            this.propsImage = "";
            const input = this.$refs.fileInput;
            input.type = "text";
            input.type = "file";
            this.$emit("updateSingleImage", 0);
            this.$emit("uploadImage", null);
          },
        }
      }

Answer №1

The warning given is quite clear that directly mutating a property is not recommended. This can lead to issues if the parent component changes the prop value, causing it to be overwritten.

A better approach would be to:

Instead of directly modifying the prop, create a reactive property within the data function and use the prop as the initial value:

props: {
  propsImage:string 
}, 
data(){
  return {
    image: this.propsImage
  }
}

If you want the image to update whenever propsImage changes, you can use a watcher:

watch: {
  propsImage(newValue){
    this.image = newValue
  }
}

To update the prop in the parent component, emit an event:

computed: {
  image: {
    get(){
      return this.propsImage
    }, 
    set(newValue)
    {
      this.$emit('update:props-image',newValue)
    }
  }
}

Remember to adjust the property binding in the parent component template to

<my-component :props-image.sync="myValue" />

It's also important to note that there is no this context available in the Vue instance within the template.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ensuring Vue.js correctly re-renders an array item

In my vue.js 2 project, I am working with an array that has the following structure: data() { return { ports: [ { id: 1, name: "example", "age": 10, scores: [ {index: 1, value: 100}, {index: 2, value: 200} ]}, { id: 2, ...

Add an image to a div element and determine its height, then apply the height to the CSS property

Here is my JavaScript code that utilizes jQuery: $(".article_big_photo").click(function() { $('#screen').css({ opacity: 0.5, 'width':$(document).width(),'height':$(document).height()}); $('#screen').show() ...

Press the Text and Alter Text with React

I'm having an issue with the onClick event using React hooks. My goal is to have the text change to a different one when the user clicks, and then revert back to the original text on another click. For example, clicking "Change First" should switch it ...

Is there a Google Maps feature that displays clusters in a dropdown

Currently, I am utilizing Google Maps to place pins all over the world and implementing markercluster.js to cluster those pins when they are nearby. One feature I am trying to incorporate is the ability to hover over a cluster of pins and have a dropdown d ...

PHP issues caused by Ajax form compatibility

I'm currently working on developing an upload website and I've encountered some challenges while trying to implement an upload progress bar. The Ajax form in my scripts seems to be causing issues with the PHP code, preventing the file from being ...

Using JavaScript to Capture a Webpage Element as an Image

Although this question has been asked in the past, I am hoping for updated information since all the answers are from a few years ago. While searching, I came across https://github.com/apollolm/phantasm, which seems to be exactly what I need. However, it ...

Monochrome Effect Triggered by Cursor Hover

I'm attempting to use Javascript with HTML5 canvas to convert an image to greyscale, but I seem to be missing something in my code. Can anyone spot the error? I feel like I'm very close! function grayscaleConversion(str) { // Access the Canv ...

Display or conceal div based on chosen options

I am working on a feature that involves three dropdown select boxes, each containing different sets of demographic attributes. My goal is to show a score based on the combination of selections made by the user. For example, if a user chooses Male, 18-24, A ...

A different component experiences an issue where Angular Promise is returning undefined

This is the carComponent.ts file containing the following method: async Download() { try { const settings = { kit: true, tyres: true, serviced: false, }; const [kits, tyres] = await Promise.all([ this.c ...

Mozilla browser experiencing issues with mouse move event functionality

Here, I have a background image on the body and with the following script, when the user moves the mouse, the image in the background also moves. body { background-image: url('../images/1.png'); background-size: 98%; background-posi ...

Unexpected behavior observed in component due to Vuex store

When attempting to access the store data in a component embedded directly in the HTML, you can use the following syntax: {{$store.state.notificationArea.cart.total;}} This method works properly. However, if trying to access the same data in the computed ...

Using mapState on a module that is not namespaced

Question about a module export default { namespaced: false, state, actions, mutations, getters }; In one of my components, I attempted the following: ...mapState(["user"]), ...mapState('auth',["user"]), Unfortunately, neither of t ...

The iteration of an ajax POST handler, looping endlessly

Attempting to implement a basic ajax submit handler for modifying a form as part of a lesson on CSRF vulnerabilities, but encountering an issue with the page looping. Below is the code snippet being worked on, inspired by http://api.jquery.com/jQuery.post/ ...

What is the best way to achieve a precision of 6 decimal places in JavaScript when working with decimals?

While working on coding to round numbers to six decimal places after performing some arithmetic operations, I encountered a problem. I was iterating through the elements of an array and conducting calculations based on the array contents. To achieve roundi ...

Saving an edited polygon path in Vue using Google Maps

In my Vue component named BaseMap, there is a nested component called Location. The Location component features an editable Polygon marker. // BaseMap <GmapMap> <Location :location="location" /> </GmapMap> // Location <gmap-marker ...

Using the $lookup aggregation stage to $group a nested array in MongoDB

I'm working with a Product Schema that is partially built using mongoose. Here's a snippet: attributes: [ { set: { ref: 'AttributeSet', type: Schema.Types.ObjectId }, items: [ ...

Occasionally, the array of image icons fails to load, but this issue is

Currently, I am encountering an issue where my app icons are not loading properly on the screen. Most of the time, everything works fine with no errors. However, occasionally (about 1 in 20 times), the icons fail to load as expected, leaving only the app n ...

Creating a stand-alone NPM module for a Redux store to be used in a React application

Can the Redux Store be developed as a separate npm package for a React App and then imported into it? For instance: Assuming there is a fictional React Project named reactapp. A package called reactapp-reduxstore is created containing the Redux Store, al ...

Exploring custom JavaScript with Construct 2's generated code

How can I access the score of a game user in Construct2 Engine using external JavaScript? Is there a method to achieve this? Appreciate any guidance on this matter. ...

What is the process for dynamically setting @click in vue.js?

My array contains objects with methods as actions from a vue object. How can I dynamically set the @click event in a v-for loop? I attempted to use this.m1, "this.m1", "m1", but encountered an error: fns.apply is not a function. Javascript: new Vue ...