我有一个具有通用堆栈的简单应用程序:
Vue应用程序使用Vuex存储库的操作从后端获取数据:
// store/store.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as MutationTypes from '@/store/mutation-types';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
investment: {},
},
mutations: {
[MutationTypes.SET_INVESTMENT_SHOW](state, investment) {
state.investment = investment;
},
},
actions: {
fetchInvestment({ commit }, id) {
InvestmentsApi.get(id).then((response) => {
commit(MutationTypes.SET_INVESTMENT_SHOW, response.data);
});
},
},
getters: {
participation: state =>
state.investment.included[0],
},
});
在组件的生命周期挂钩中调用该操作,如下所示:
// components/Investment.vue
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'Investment',
computed: {
...mapState(['investment']),
...mapGetters(['participation']),
},
created() {
this.fetchData(this.$route.params.id);
},
methods: mapActions({
fetchData: 'fetchInvestment',
}),
};
我上面编写的代码有问题,实际上我在模板中使用了计算值“参与”:
<BaseTitleGroup
:subtitle="participation.attributes.name"
title="Investissements"
/>
当然,因为我在组件呈现自身时使用了参与性,所以我会从getter方法获得此错误:
Error in render: "TypeError: Cannot read property '0' of undefined"
found in
---> <InvestmentSummary> at src/views/InvestmentSummary.vue
<App> at src/App.vue
<Root>
我认为有多种解决方案可以解决此问题,我想知道哪种方法是最佳实践,或者是否有更好的方法。
我正在寻找最好的解决方案来处理这种模式,即使它是上述之一,但我不确定哪个是最好的。非常感谢您的阅读!另外,我使用vue框架,但我认为这更多是关于异步数据和呈现的现代javascript框架处理的一般问题。
很抱歉,很长的帖子,这是土豆! (糟糕,不是在9gag上;))
答案 0 :(得分:1)
我认为没有最好的解决方案,只需选择一种并在各处使用它,而不要混合使用。
v-if
可能更好,以防您要从嵌套属性渲染数据-v-if="object.some.nested.property v-for="el in object.some.nested.property"
可以工作,但预定义object = {}
则不能(它会抛出错误,{ {1}}未定义,您正在尝试访问它。
我不会像您的示例中那样放置任何假数据,但是您可以使用ES6 Classes定义默认对象并将其设置为默认值。只要您的类对象具有适当的结构(并且它在语法上也是透明的并且易于理解),这也可以解决上述预定义问题。
关于第三个选项-将空数据提供给getter不必太复杂-只需将getter更改为:
some
如果已定义,则使用getters: {
participation: state =>
state.investment.included[0] || new DefaultParticipationObject() // I don't know what's in included array
},
,否则使用默认对象。
答案 1 :(得分:1)
在Angular中,有Elvis(安全导航)运算符,这是处理 最终 到达的反应性数据的简洁方法。
如果在Vue模板编译器中可用,则您的模板将如下所示:
<BaseTitleGroup
:subtitle="participation?.attributes?.name"
title="Investissements"
/>
但是,Evan You说it sounds like a code smell。
您的模型/状态应该尽可能地可预测。
尝试将注释扩展到您的上下文中,我认为这意味着 您的模板比您的商店更了解您的数据结构 。
模板
"participation.attributes.name"
等于:
state.investment.included[0].attributes.name
商店
state: {
investment: {},
},
由于吸气剂在那里可以为组件(及其模板)提供服务,所以我会选择增强吸气剂。
getters: {
participation_name: state => {
return
(state.investment.included
&& state.investment.included.length
&& state.investment[0]
&& state.investment[0].attributes
&& state.investment[0].attributes.name)
|| null;
},
<BaseTitleGroup
:subtitle="participation_name"
title="Investissements"
/>
但是,如果您想要Elvis功能,则可以在mixin中提供它。
var myMixin = {
computed: {
elvis: {
get: function() {
return (known, unknown) => {
// use regex split to handle both properties and array indexing
const paths = unknown.split(/[\.(\[.+\])]+/);
let ref = known
paths.forEach(path => { if (ref) ref = ref[path] });
return ref;
}
}
},
}
}
export default {
name: 'Investment',
...
mixins: [myMixin],
computed: {
...mapState(['investment']),
participation_name() {
return this.elvis(this.investment, 'included[0].attributes.name')
}
},
...
};