成功调用 axios 后,Vue.js 组件不会发送到父级
Posted
技术标签:
【中文标题】成功调用 axios 后,Vue.js 组件不会发送到父级【英文标题】:Vue.js component does not emit to parent after successful axios call 【发布时间】:2020-02-15 09:12:19 【问题描述】:我正在使用
"axios": "^0.19.0",
"vue": "^2.6.10",
"vuex": "^3.1.1"
我的vuex
操作看起来像这样,并使用axios
调用远程接口。该请求确实有效并收到了有效的响应。
skipQuestion(commit, payload)
let params =
answer:
id: payload.id,
skipped: true,
;
return new Promise((resolve, reject) =>
commit(UPDATE_LOADING, true);
Remote.put(`/answer.json`, params)
.then((response) =>
commit(UPDATE_LOADING, false);
commit(SKIP_QUESTION, payload.id);
resolve();
)
.catch((error) =>
commit(UPDATE_LOADING, false);
reject(error);
)
)
,
组件Question
确实具有以下方法skip
,它调用vuex
操作skipQuestion
并应该向父组件发出skip
事件。
...mapActions(['skipQuestion']),
skip(evt)
let payload = id: this.question_id ;
this.skipQuestion(payload).then( () =>
this.$emit('skip', this.uuid);
).catch( (error) =>
console.log(error);
);
,
问题是,skip
事件在操作的 then
块中使用时不会发送给父级。 chrome 的 vue 开发者控制台也确认,skip
事件已被触发。如果我将发射放在块外,一切正常。有什么建议吗?
编辑 1
还尝试了以下代码,两个日志语句都打印到控制台。
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);
);
,
编辑 2
这是用于监听子事件的模板代码:
<question v-bind="question"
:key="question.uuid"
v-if="questionReady"
v-on:skip="onSkipQuestion"
v-on:answer="onAnswerQuestion">
</question>
如前所述,如果不使用由axios
请求返回的 Promise/then-block,则发出确实有效。您将在下面找到应该调用的方法:
methods:
onSkipQuestion(payload)
// this code is not executed
console.log('onSkipQuestion')
//....
,
//....
【问题讨论】:
也许不是您问题的最终解决方案,但您绝对应该尝试切换到 await / async 而不是使用原始承诺 我假设你的父组件上有类似v-on:skip=somfunc
的东西来收听skip
事件。对吗?
是的,当然,我也试过@skip=somefunc
。如前所述,如果我在 then
块之外发出它,一切正常。
你能添加你的模板代码吗?
也许尝试使用.bind()
这个方法,那么也许你的父组件也会看到这个事件。或者尝试在data() return skip: () => ....
中创建skip
箭头功能
【参考方案1】:
总结您给出的信息:
用于 chrome 的 vue 开发者控制台也确认已触发跳过事件。
TL;DR
vm.$emit
基本上调用vm._events[eventName]
中列出的每个方法
v-on
在createElemet
中通过context.listeners
注册并通过updateListeners
注入
基本上可以使用debugger
语句进行调试:
skip(evt)
let payload = id: this.question_id ;
this.skipQuestion(payload).then( () =>
debugger; // scope -> _events & scope -> $parent.componentInstance
// or console.log(JSON.stringify(this._events))
this.$emit('skip', this.uuid);
).catch( (error) =>
console.log(error);
);
,
那你就知道发生了什么了。
检查事项:
有效的this
范围
有效parent
实际触发为已解决
vm._events
已注册
【讨论】:
【参考方案2】:您在 then 块中丢失了对 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);
);
,
【讨论】:
谢谢,我之前尝试过,但没有任何改变。该事件不会发送给父级。 奇怪....你确认then
被阻止是通过添加console.log语句来调用的吗?
是的,我在emit
之前和之后添加了一个console.log
,两者都打印在then
块中。确实更新了代码示例。
如果您将this
更改为vm,那么在emit 语句中this.uuid
也应该更改。【参考方案3】:
也许问题是你没有在skipQuestion() 中返回resolve() 或reject()。
无论如何,假设您的应用程序使用 ES2017(或更高版本),或者如果不是,则使用 Babel,我会改进函数以使用 async / await
结构,以便 @987654323 @ 不会有任何风险(参考Varun's answer),如果skipQuestion()
没有返回任何东西,也不会有任何风险,就像目前一样:
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);
在 Promise((resolve, reject) => ...)
语法的情况下,不返回 resolve / reject
是已知的错误来源
【讨论】:
感谢您的回答。目前我们正在使用Babel
。我们尝试了您的更新代码,还删除了额外的 Promise
的返回,但仍然没有将 emit 提升到父组件。
你是什么意思“删除了额外的承诺的回报”?您可以编辑您的问题并添加您所做的更改吗?
商店操作现在返回return Remote.put(
/answer.json, params) .then((response) => commit(UPDATE_LOADING, false); ) .catch((error) => commit(UPDATE_LOADING, false); )
你不需要删除 promise 语法。无论如何,请在 then
和 catch
块中返回一些东西!您在启动 skipQuestion() 时使用 then
和 catch
,我认为它不会被命中,因为没有返回任何内容
您能否举一个例子来说明您的陈述“不返回解决/拒绝是已知的错误来源” - 这不应该是 o0 的情况?至少对于承诺状态 - 除非你在承诺内解决/拒绝后运行阻塞代码......我很好奇【参考方案4】:
我也遇到了同样的问题,我终其一生都无法弄清楚发生了什么。我能想到的是,在等待承诺解决方案时,组件以某种方式失去了发出事件的能力。
无论如何,我的解决方案是自己发出承诺,如下所示:
skip(evt)
let payload = id: this.question_id ;
this.$emit('skip', skipQuestion(payload));
在父级上,你可以这样做
... @skip="receive_skip($event)" ...
...
methods:
receive_skip(skipped)
skipped
.then((data) =>
// do something on success
)
.catch((err) =>
// do something on fail
);
它没有那么干净和优雅,但它完成了工作。
【讨论】:
以上是关于成功调用 axios 后,Vue.js 组件不会发送到父级的主要内容,如果未能解决你的问题,请参考以下文章