Vuex状态未完全更新同级控件

时间:2019-12-17 13:52:31

标签: vuejs2 vuex

我在Vuex和同级组件状态更新方面遇到问题。我知道有必要使用:key绑定。

我的状态是:

    filters: {
      clientId: 0,
      projectId: 0,
      projectRoleId: 0,
      subProjectId: 0,
    },

我有4个组成该页面的组件:

:此组件具有子组件,但具有过滤器的v-处于此级别

DailyDetail (每日详细信息):该组件显示了一天的时间条目,其中包含更多详细信息

议程:这是日历中显示的同一天的垂直视图(月控制)

过滤器:在这里我们可以过滤4个字段(客户,项目,子项目或项目角色)中的1个

当我单击并添加过滤器时,所有3个组件(“月”,“每日详细信息”和“议程”)都仅显示过滤的结果。这就是我要的。 但是,当我单击“过滤器”控件上的“清除过滤器” 按钮时,似乎只有“月份”组件会注意到它。其他只是保持不变。从filtered getter更改时正确应用和删除hasFilters类的事实出发。

如果有帮助,请参见以下动作/突变和获取器:

过滤器的设置直接从计算的设置器中获取突变:

    // 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>

以下是这些组件的吸气剂:

    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
          : [];
      }
    },

这里是将议程组件进行了一些微调,以仅显示有用的信息:

    <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吸气剂在其组件上应用名为filtered的类,以表示存在过滤器。此部分适用于设置和清除过滤器。问题在于,清除过滤器后,进入过滤器(该部分有效)时过滤掉的值不会被清除。 Month组件运行良好,但是Agenda和DailyDetails只是保持过滤状态。

1 个答案:

答案 0 :(得分:0)

好吧,经过一夜的睡眠,我想我会再戳一遍。这是我的错(正如预期的那样)。我注意到两件事,一是DailyDetail组件正确显示了filtered类(如上所述),但是 not 过滤数据。这样的解决方法就在这里:

未过滤的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组件(一个不起作用的组件)并不是使用JavaScript {{1 }}方法,它还需要做更多的工作并提取出不需要的内容。

答案这是filter将不需要的内容从数组中覆盖,从而覆盖了原始数组,因此,当关闭过滤功能时,没有任何内容可返回。因此,我制作了阵列的副本,现在所有3个组件都可以工作!

用于议程的原始获取程序,它已进行过滤并完全删除

filter

更新的议程吸气剂(只是更改),可以在过滤器之前复制数组

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;
},

这是问题所在的特定行,需要该数组的副本:

// 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) ));