vuejs2 - Vuex 状态未完全更新兄弟控件
问题描述
我在使用 Vuex 和将状态更新为兄弟组件时遇到问题。我知道:key
绑定的必要性并拥有它。
在我的状态下,我有:
filters: {
clientId: 0,
projectId: 0,
projectRoleId: 0,
subProjectId: 0,
},
我有 4 个组成这个页面的组件:
Month:这个组件有子组件,但是有过滤器的 v-for 在这个级别
DailyDetail:此组件显示一天的时间条目,并提供更多详细信息
议程:这是日历中显示的同一天的垂直视图(月份控制)
过滤器:在这里我们可以过滤 4 个字段中的 1 个(客户、项目、子项目或项目角色)
当我单击并添加过滤器时,所有 3 个组件(月、每日详细信息和议程)都仅显示过滤后的结果。这就是我要的。但是,当我单击 Filters 控件上的Clear Filters按钮时,似乎只有 Month 组件会注意到它。其他的只是保持不变。除了当getter 更改filtered
时该类被正确应用和删除的事实。hasFilters
如果有帮助,这里是动作/突变和吸气剂:
过滤器的设置直接从计算的 setter 转到 Mutation:
// Computed properties on the Filter component:
filteredClientId: {
get() { return this.$store.state.time.filters.clientId; },
set(value) { this.$store.commit('time/SET_FILTERED_CLIENT', value); },
},
filteredProjectId: {
get() { return this.$store.state.time.filters.projectId; },
set(value) { this.$store.commit('time/SET_FILTERED_PROJECT', value); },
},
filteredProjectRoleId: {
get() { return this.$store.state.time.filters.projectRoleId; },
set(value) { this.$store.commit('time/SET_FILTERED_PROJECT_ROLE', value); },
},
filteredSubProjectId: {
get() { return this.$store.state.time.filters.subProjectId; },
set(value) { this.$store.commit('time/SET_FILTERED_SUB_PROJECT', value); },
},
// Here are the corresponding mutations
SET_FILTERED_CLIENT(state, value) {
state.filters.clientId = value;
},
SET_FILTERED_PROJECT(state, value) {
state.filters.projectId = value;
},
SET_FILTERED_PROJECT_ROLE(state, value) {
state.filters.projectRoleId = value;
},
SET_FILTERED_SUB_PROJECT(state, value) {
state.filters.subProjectId = value;
},
这是月份组件(此组件始终可以设置和清除过滤器):
<template>
<div class="month"
:class="{ 'filtered': hasFilters }"
>
<weekDays />
<week v-for="(week, index) in weeks"
:key="index"
:week="week"
/>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import week from './week.vue';
import weekDays from './weekDays.vue';
export default {
components: {
week,
weekDays,
},
computed: {
...mapGetters('time', ['hasFilters', 'weeks']),
},
};
</script>
以下是这些组件的 getter:
daysWithinPayPeriod: (state, getters) => {
if (!state.currentDay) // This is simply to gracefully exit when no data is loaded yet
return [];
let payPeriodSerial = state.currentDay.PayPeriodSerial;
// Find all of the entries within the pay period
let validDays = state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial);
if (getters.hasFilters) {
for (let day of validDays) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return validDays;
},
hasFilters: state => {
return state.filters.clientId !== 0 ||
state.filters.projectId !== 0 ||
state.filters.projectRoleId !== 0 ||
state.filters.subProjectId !== 0;
},
weeks: (state, getters) => {
if (getters.hasFilters) {
let result = JSON.parse(JSON.stringify(state.monthlyData.Weeks));
for (let week of result) {
for (let day of week.Days) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return result;
} else {
return state.monthlyData.Weeks
? state.monthlyData.Weeks
: [];
}
},
下面是 Agenda 组件,它被修剪了一点,只显示有用的信息:
<template>
<div class="agenda">
<table class="table table-hover mb-0 table-bordered"
:class="{ 'filtered': hasFilters }"
>
...
<tbody>
<tr v-for="day in daysWithinPayPeriod"
:key="day.DayOfYear"
:class="{ 'is-today': day.IsToday, 'weekend': day.IsWeekend, 'focused': isDaySelected(day) }"
class="day-row"
@click="selectDay(day)"
>
...
<td colspan="4"
class="breakout"
>
<table v-if="day.ProjectTimes.length > 0"
class="table table-sm table-striped table-hover table-borderless mb-0"
>
<tbody>
<tr v-for="entry in day.ProjectTimes"
:key="entry.ID"
>
...
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import store from '../../store';
export default {
store: store,
mixins: [ formattingFilters ],
computed: {
...mapGetters('time', ['daysWithinPayPeriod', 'hasFilters']),
...mapState('time', {
}),
},
methods: {
selectDay(day) {
this.$store.dispatch('time/dateSelected', day);
},
},
};
</script>
对于议程组件,我假设它是嵌套v-for
的,但是 DailyDetail 组件(要遵循)没有嵌套v-for
并且不会“清除”过滤器。
这是 DailyDetail 组件:
<template>
<div class="daily-detail">
<table class="table table-sm table-striped table-hover mb-0"
:class="{ 'filtered': hasFilters }"
>
...
<tbody>
<tr v-for="entry of currentDaysTimeEntries"
:key="entry.ID"
:class="{ 'italic': entry.Project.IsUniversal }"
>
<td class="text-center"><i class="far fa-pencil" /></td>
<td><div class="text-right">{{ entry.Time | formatNumber }}</div></td>
<td>
<div class="truncate">{{ entry.Project.Name }}</div>
<div v-if="entry.SubProject.ID > 0"
class="subproject"
>
{{ entry.SubProject.Name}}
</div>
<small>{{ entry.Project.Client.Name }}</small>
</td>
...
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import store from '../store';
import formattingFilters from '../mixins/formatting';
export default {
store: store,
computed: {
...mapGetters('time', ['currentDaysTotalTime', 'currentDaysTimeEntries', 'hasFilters', 'selectedDate']),
},
};
</script>
过滤器的清除通过一个动作:
// Action
clearFilters(context) {
context.commit('CLEAR_FILTERS');
},
// Mutation
CLEAR_FILTERS(state) {
state.filters.clientId = 0;
state.filters.projectId = 0;
state.filters.projectRoleId = 0;
state.filters.subProjectId = 0;
},
所以重申一下,问题在于所有 3 个组件都使用hasFilters
getter 来应用一个调用filtered
其组件的类,以表示有过滤器在起作用。这部分适用于设置和清除过滤器。问题是,当过滤器在(该部分有效)时被过滤掉的值在过滤器被清除时不会被清除。Month 组件完美运行,但 Agenda 和 DailyDetails 只是保持过滤状态。
解决方案
好吧,睡了一夜好觉后,我想我会再戳一下它。这是我的错(正如预期的那样。)我注意到两件事,一是DailyDetail
组件filtered
正确显示了类(如上所述)但是,它没有过滤数据。所以修复就在这里:
原来的吸气剂DailyDetail
没有过滤
currentDaysTimeEntries: state => {
return state.currentDay
? state.currentDay.ProjectTimes
: [];
},
修复DailyDetail
了过滤的吸气剂
currentDaysTimeEntries: (state, getters) => {
if (state.currentDay) {
if (getters.hasFilters) {
return state.currentDay.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
} else {
return state.currentDay.ProjectTimes;
}
} else {
return [];
}
},
然后,一旦解决了这个问题并且 3 个组件中的 2 个运行良好,我意识到该Agenda
组件(那个不工作的)不仅仅是使用 JavaScriptfilter
方法,它必须做更多的事情并提取出它不需要的东西。
回答它是filter
从数组中删除不需要的东西,覆盖原始数组,因此当过滤被关闭时,没有什么可回头了。所以我制作了一个数组的副本,现在所有 3 个都可以工作了!
议程的原始吸气剂,WAS 过滤并完全删除
daysWithinPayPeriod: (state, getters) => {
if (!state.currentDay)
return [];
let payPeriodSerial = state.currentDay.PayPeriodSerial;
// Find all of the entries within the pay period
let validDays = state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial);
if (getters.hasFilters) {
for (let day of validDays) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return validDays;
},
更新了在过滤器之前复制数组的议程 getter(只是更改)
// Find all of the entries within the pay period and make a copy
let validDays = JSON.parse(JSON.stringify(
state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial)
));
这是问题所在的特定行,需要数组的副本:
day.ProjectTimes = day.ProjectTimes.filter(x => {
推荐阅读
- r - 我的时期`.`将使用dplyr而不是ggplot管道数据框
- ios - 集合视图仅作为整个视图的一部分
- django - CondaHTTPError:URL 的 HTTP 000 连接失败
- pine-script - 在编写指标脚本时需要帮助
- python - 从具有多个页面结果的网站抓取网页
- python - 迭代某些行
- javascript - 使用 d3 增加节点链接图中的链接长度
- ios - 我遇到了一个我不理解且无法使用 Swift 自行修复的错误。我的问题不同。看看我提供的代码。谢谢
- python - 如何导入模块 apply_transform 或替换为其他模块?
- git - 从源代码管理中删除项目而不删除解决方案的其余部分