admin管理员组

文章数量:1334373

I am using

"axios": "^0.19.0",
"vue": "^2.6.10",
"vuex": "^3.1.1"

My vuex action looks like this and calls a remote interface using axios. The request does work and it receives a valid response.

skipQuestion({mit}, payload) {
    let params = {
        answer: {
            id: payload.id,
            skipped: true,
        }
    };

    return new Promise((resolve, reject) => {
        mit(UPDATE_LOADING, true);
        Remote.put(`/answer.json`, params)
            .then((response) => {
                mit(UPDATE_LOADING, false);
                mit(SKIP_QUESTION, payload.id);
                resolve();
            })
            .catch((error) => {
                mit(UPDATE_LOADING, false);
                reject(error);
            })
    })
},

The ponent Question does have the following method skip, which calls the vuex action skipQuestion and should emit the skip event to the parent ponent.

...mapActions(['skipQuestion']),
skip(evt) {
    let payload = { id: this.question_id };
    this.skipQuestion(payload).then( () => {
        this.$emit('skip', this.uuid);
    }).catch( (error) => {
        console.log(error);
    });
},

The problem is, that the skip event is not emitted to the parent when using it within the then block of the action. The vue developer console for chrome also confirms, that the skip event was fired. If I put the emit outside the block, everything works. Any suggestions whats going wrong?

Edit 1

Also tried the following code and both log statements are printed to the console.

skip(evt) {
    let payload = { id: this.question_id };
    let vm = this; 
    this.skipQuestion(payload).then( () => {
        console.log('before skip emit');
        vm.$emit('skip', this.uuid);
        console.log('after skip emit');
    }).catch( (error) => {
        console.log(error);
    });
},

Edit 2

Here is the template code which is used to listen to the child events:

<question v-bind="question"
          :key="question.uuid"
          v-if="questionReady"
          v-on:skip="onSkipQuestion"
          v-on:answer="onAnswerQuestion">
</question>

As told before, if not using the Promise/then-block returned by the axios request, the emit does work. Below you'll find the method which should be called:

methods: {
  onSkipQuestion(payload) {
    // this code is not executed
    console.log('onSkipQuestion')

    //....
  },


  //....
}      

I am using

"axios": "^0.19.0",
"vue": "^2.6.10",
"vuex": "^3.1.1"

My vuex action looks like this and calls a remote interface using axios. The request does work and it receives a valid response.

skipQuestion({mit}, payload) {
    let params = {
        answer: {
            id: payload.id,
            skipped: true,
        }
    };

    return new Promise((resolve, reject) => {
        mit(UPDATE_LOADING, true);
        Remote.put(`/answer.json`, params)
            .then((response) => {
                mit(UPDATE_LOADING, false);
                mit(SKIP_QUESTION, payload.id);
                resolve();
            })
            .catch((error) => {
                mit(UPDATE_LOADING, false);
                reject(error);
            })
    })
},

The ponent Question does have the following method skip, which calls the vuex action skipQuestion and should emit the skip event to the parent ponent.

...mapActions(['skipQuestion']),
skip(evt) {
    let payload = { id: this.question_id };
    this.skipQuestion(payload).then( () => {
        this.$emit('skip', this.uuid);
    }).catch( (error) => {
        console.log(error);
    });
},

The problem is, that the skip event is not emitted to the parent when using it within the then block of the action. The vue developer console for chrome also confirms, that the skip event was fired. If I put the emit outside the block, everything works. Any suggestions whats going wrong?

Edit 1

Also tried the following code and both log statements are printed to the console.

skip(evt) {
    let payload = { id: this.question_id };
    let vm = this; 
    this.skipQuestion(payload).then( () => {
        console.log('before skip emit');
        vm.$emit('skip', this.uuid);
        console.log('after skip emit');
    }).catch( (error) => {
        console.log(error);
    });
},

Edit 2

Here is the template code which is used to listen to the child events:

<question v-bind="question"
          :key="question.uuid"
          v-if="questionReady"
          v-on:skip="onSkipQuestion"
          v-on:answer="onAnswerQuestion">
</question>

As told before, if not using the Promise/then-block returned by the axios request, the emit does work. Below you'll find the method which should be called:

methods: {
  onSkipQuestion(payload) {
    // this code is not executed
    console.log('onSkipQuestion')

    //....
  },


  //....
}      
Share edited Oct 23, 2019 at 7:47 anka asked Oct 18, 2019 at 11:14 ankaanka 3,8571 gold badge31 silver badges38 bronze badges 5
  • 1 Maybe not the definitive solution to your problem, but you should definitely try switching to await / async instead of using raw promises – coyotte508 Commented Oct 18, 2019 at 11:17
  • I'm assuming that you have on your parent ponent something like v-on:skip=somfunc to listen to the skip event. is that right? – Carlos Crespo Commented Oct 22, 2019 at 9:46
  • Yes of course, I also tried @skip=somefunc. As mentioned if I emit it outside the then block everything works fine. – anka Commented Oct 22, 2019 at 13:18
  • Can you add your template code ? – Pierre Burton Commented Oct 22, 2019 at 14:27
  • Maybe try to use .bind() for this method, then maybe your parent mponent will also see this event. Or maybe try to make skip arrow function inside data() {return { skip: () => ....}} – Krzysztof Kaczyński Commented Oct 26, 2019 at 9:46
Add a ment  | 

4 Answers 4

Reset to default 4

Summarize your information given:

The vue developer console for chrome also confirms, that the skip event was fired.


TL;DR

  • vm.$emit bassically calls every method listed in vm._events[eventName]

  • v-on gets registered via context.listeners in createElemet and injected via updateListeners


Basically you can debug using debugger statement:

skip(evt) {
    let payload = { id: this.question_id };
    this.skipQuestion(payload).then( () => {
        debugger; // scope -> _events & scope -> $parent.ponentInstance
        // or console.log(JSON.stringify(this._events))
        this.$emit('skip', this.uuid);
    }).catch( (error) => {
        console.log(error);
    });
},

Then you know whats happening.


Things to check:

  • valid this scope

  • valid parent

  • actually triggered as resolved

  • vm._events registered

You have lost the reference to this inside the then block. The reference is now the callback function called. Instead do this

 ...mapActions(['skipQuestion']),
    skip(evt) {
        let payload = { id: this.question_id };
        let vm = this; // Preserve Vue instance for use inside block
        this.skipQuestion(payload).then( () => {
            vm.$emit('skip', vm.uuid);
        }).catch( (error) => {
            console.log(error);
        });
    },

Maybe the problem is that you don't return resolve() or reject() in skipQuestion().

Anyway, assuming your application uses ES2017 (or higher), or if not then Babel, I would refine the function to use async / await structure so that this would not be at any risk (referring to Varun's answer), and not in any risk if skipQuestion() doesn't return anything, like as is currently:

async skip(evt) {
    let payload = { id: this.question_id };
    try {
      let result = await skipQuestion(payload)
      this.$emit('skip', this.uuid);
    } catch(error){
      console.log(error);
    }
}

Not returning resolve / reject is a known source of bugs in case of Promise((resolve, reject) => {...}) syntax

I had this exact same problem and could not for the life of me figure out what was going on. All I can think of is that somehow the ponent is losing the ability to emit events while awaiting the promise resolution.

Anyway, my solution was to emit the promise itself, like this:

skip(evt) {
    let payload = { id: this.question_id };
    this.$emit('skip', skipQuestion(payload));
}

And on the parent, you can do

... @skip="receive_skip($event)" ...

...

methods: {
    receive_skip(skipped) {
        skipped
        .then((data) => {
            // do something on success
        })
        .catch((err) => {
            // do something on fail
        });
    }
}

It's not as clean and elegant, but it gets the job done.

本文标签: javascriptVuejs component does not emit to parent after successful axios callStack Overflow