VUEX筛选的计算属性不会在状态更改时更新

时间:2020-03-06 19:50:11

标签: vue.js vuex

我正在使用vuex,并且使用getters Iam过滤存储中的数据数组。

在父组件中,我正在获取数组并将其发送给带有道具的孩子。 子组件使用getter过滤筛选的数组,并将其保存在计算属性中。 但是,当我通过调用操作进行更改时,存储被更新,但过滤后的数组保持不变。

当我将未过滤的原始数组发送给子组件时,它很不错。 它是vue开发工具,我可以看到正确的更新的吸气剂。

下面是一些代码。

存储

const getDefaultState = () => {
    return {
        activities: [],
        error: null,
        isActivitiesLoading: false,
        isActivityUpdating: false,
    }
}

const mutations = {
    [FETCHING_ACTIVITIES](state) {
        state.isActivitiesLoading = true;
        state.error = null;
    },
    [FETCHING_ACTIVITIES_SUCCESS](state, activities) {
        state.error = null;
        state.isActivitiesLoading = false;
        state.activities = activities
    },
    [FETCHING_ACTIVITIES_ERROR](state, error) {
        state.error = error;
        state.isActivitiesLoading = false
    },
    [UPDATING_ACTIVITY](state) {
        state.isActivityUpdating = true;
        state.error = null;
    },
    [UPDATING_ACTIVITY_SUCCESS](state, activity) {
        state.error = null;
        state.isActivityUpdating = false;
        const index =  state.activities.findIndex(a => a.id === activity.id)
        state.activities[index] = activity;
    },
    [UPDATING_ACTIVITY_ERROR](state, error) {
        state.error = error;
        state.isActivityUpdating = false
    },
}
const actions = {
    async fetchActivities({ commit }) {
        commit(FETCHING_ACTIVITIES);
        try {
            const response = await ActivitiesApi.fetchActivities();
            const activities = response.data.data;
            commit(FETCHING_ACTIVITIES_SUCCESS, activities);
            return response.data.data;
        } catch (error) {
            commit(FETCHING_ACTIVITIES_ERROR, error);
            return null;
        }
    },
    async updateActivity({ commit }, payload) {
        commit(UPDATING_ACTIVITY);
        try {
            const response = await ActivitiesApi.updateActivity(payload);
            const activity = response.data.data;
            commit(UPDATING_ACTIVITY_SUCCESS, activity);
            return response.data.data;
        } catch (error) {
            commit(UPDATING_ACTIVITY_ERROR, error);
            return null;
        }
    },
};
const getters = {
    getActivities(state) {
        return state.activities;
    },
    getRunningActivities(state) {
        let today = new Date();
        const activities =  state.activities;
        const filteredActivities = activities.filter(function(activity) {
            let activityDate = new  Date(activity.start_date)
            return activityDate <= today
        });
        return filteredActivities;
    },
};

export default {
    namespaced: true,
    state: getDefaultState(),
    getters,
    actions,
    mutations,
}

父组件

<template>
  <div class="container">
    <h3>Running Activities</h3>
    <ActivitiesComponent 
      :initialActivitiesFromStore="runningActivities" 
    />
  </div>
</template>
import ActivitiesComponent from "../components/Activities";

export default {
  components: {
    ActivitiesComponent
  },
  mounted() {
     this.$store.dispatch('activities/fetchActivities').then(
        () => {
            if (this.hasError) {
                console.log(this.error)
            } else {
            }
        }
    );
  },
  computed: {
    activitiesFromStore() {
      return this.$store.getters['activities/getActivities'];
    },
    runningActivities() {
      return this.$store.getters['activities/getRunningActivities']
    },
  },

}
</script>

儿童组件

<template>
  <div class="container">
    <div v-if="isActivitiesLoading" class="spinner-border spinner"></div>
      <div class="row">
          <div class="col">
            <table class="table">
              <thead>
                <tr>
                  <th scope="col">#</th>
                  <th scope="col">Activities</th>
                  <th scope="col">Period</th>
                  <th scope="col"></th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(activity, activityId) in $v.activities.$each.$iter" :key="activityId">
                  <th scope="row">{{ parseInt(activityId) + 1 }}</th>
                  <td>
                    <input type="text" class="form-control" v-model="activity.name.$model">
                    <div class="alert alert-danger" v-if="!activity.name.required">Print Name</div>
                    <div v-if="activitiesFromStore[activityId].is_paused" class="alert alert-warning">
                      Activity is paused
                    </div>
                  </td>
                  <td>
                    <input type="text" class="form-control" v-model="activity.activity_period.$model">
                    <div class="alert alert-danger" v-if="!activity.activity_period.required">Print period</div>  
                    <div class="alert alert-danger" v-if="!activity.activity_period.integer || !activity.activity_period.minValue">Period > 0</div>  
                  </td>
                  <td class="d-flex border-0">
                    <button  @click="activity.$model.is_paused = ! activity.$model.is_paused" class="btn btn-light mr-1" v-bind:class="{ active: !activity.$model.is_paused }">
                      <span v-if="activity.$model.is_paused">Убрать с паузы</span>
                      <span v-else>Make pause</span>
                    </button>
                    <button @click="updateActivity(activity.$model)" :disabled="
                    isActivityUpdating || !activitiesChanged(activityId) || !activity.name.required || !activity.activity_period.required || !activity.activity_period.integer || !activity.activity_period.minValue
                    " type="button" class="btn btn-success mr-1">
                        <span v-if="isActivityUpdating && activityActed.id == activity.$model.id" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                          Change
                      </button>
                    <button @click="deleteActivity(activity.$model)" type="button" class="btn btn-danger">
                        <span v-if="isActivityDeleting && activityActed.id == activity.$model.id" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                          Delete
                    </button>
                  </td>
                </tr>
              </tbody>
            </table>
            <div class="collapse"  id="collapseExample">
                <div class="form-group row">
                    <div class="col-4">
                        <label for="newPassword-input">Name</label>
                        <input v-model="activityToAdd.name" class="form-control"> 
                        <div v-if="$v.activityToAdd.period.$dirty && !$v.activityToAdd.name.required" class="alert alert-danger">Print name</div>                   
                    </div>
                    <div class="col-4">
                        <label for="newPassword-input">Period</label>
                        <input  v-model="activityToAdd.period" class="form-control">
                    <div class="alert alert-danger" v-if="$v.activityToAdd.period.$dirty && !$v.activityToAdd.period.required">Print period</div>  
                    <div class="alert alert-danger" v-if="(!$v.activityToAdd.period.integer || !$v.activityToAdd.period.minValue)">period > 0</div>                  
                    </div>
                </div>
                <button @click="addActivity" :disabled="!$v.activityToAdd.name.required || !$v.activityToAdd.period.required || !$v.activityToAdd.period.integer || !$v.activityToAdd.period.minValue" type="button" class="btn btn-primary">
                  <span v-if="isActivityAdding" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                  add
                </button>
            </div>
          </div>
      </div>
  </div>
</template>

<script>
import {required, minValue, integer} from "vuelidate/lib/validators"

export default {
    props: ['initialActivitiesFromStore'],
    data() {
        return {
            activityActed: null,
            justEdited: false,
            justAdded: false,
            justDeleted: false,
            activityToAdd:{
                name: '',
                period: '',
                isPaused: ''
            }
        }
  },

  computed: {
    activitiesFromStore() {
      return this.initialActivitiesFromStore
    },
    activities() {
      return JSON.parse(JSON.stringify(this.initialActivitiesFromStore));
    },
  },
  methods: {
    activitiesChanged(id) {
      if(this.activitiesFromStore[id] &&  this.activities[id].name == this.activitiesFromStore[id].name && this.activities[id].activity_period == this.activitiesFromStore[id].activity_period && this.activities[id].is_paused == this.activitiesFromStore[id].is_paused)
        return false;
      else
        return true  
    },
    updateActivity(activity){
      this.activityActed = activity;
      this.$store.dispatch('activities/updateActivity', activity).then(
              () => {
                  if (this.hasError) {
                      console.log(this.error)
                  } else {
                    this.justEdited = true;
                    // still the same
                    console.log(this.$store.getters['activities/getRunningActivities']);
                  }
              }
          );
    },
  },
  validations: {
    activities: {
      $each: {
        name: {
          required,
        },
        activity_period: {
          required,
          integer,
          minValue: minValue(0)
        },
        is_paused: {
          required,
        },
      }
    },

  }
}
</script>

1 个答案:

答案 0 :(得分:0)

问题是我没有遵循有关修改数组的vue规范。我使用了vm.items[indexOfItem] = newValue,它不是被动的。