Barry van Biljon
Barry van Biljon

Reputation: 41

Vuex State not Reactive without Page reload

The problem experiences entails the following setup: Simple Nuxt Intallation v2^ Using Vuetify and Axios

I have already built an advanced app with a lot of extras using a real back-end, but decided to replicate the error on a simple new installation of Nuxt just to be able to create a repo for you guys. So the functionality of this demo might not be clear to you - but in real life the app is using tasks and projects. The user must be able to change the status of each task.

I cannot figure out how to go further with this app if I can't implement this feature. My first thoughts are that it might be a bug with Nuxt / Vue - but I'm hoping someone can tell me I'm wrong!

Seems simple?! Well, 7 Days later and I'm no closer to solving this little bug I am experiencing...

Well for your ease-of-access I have loaded a simple github demo showing just what the problem is with only 3 steps to reproduce the error.

https://github.com/BarryJamez/not-so-reactive-app.git

Steps: Once you have run 'npm run dev' - as follows:

Step 1: Start on the index page (http://localhost:3000)

Step 2: Click on 'View Tasks'

Step 3: Try to change the status of a task by pressing the buttons

Step 4: Now refresh the page and all of a sudden it works.

To repeat this problem, just navigate back to the home page, refresh (reload) the page and start again from step 1

I have tried a lot of things, but none of them worked:

**1. I have moved my entire child component housing the list of comments into the parent component to eliminate the passing of props being the problem.

  1. I have used Vue.set and array.splice instead of just replacing the array item with an index

  2. I have enabled watchers on these computed arrays and set 'deep' to true

  3. I have played around with async and await by removing them and adding them on certain places.

  4. I have used the $nextTick function to see if it was a render issue

  5. I have placed the array in its own parent level state property (although the postId field in a child element in the array) - yet how else can I contain an object in a state - an object must have 'child' elements.

  6. I have referenced the parent component computed properties instead of the props in the child component.**

My Page with the tasks:

<template>
  <v-container fluid>
    <v-row v-for="task in myTasks" :key="task.id">
      <v-col>
        <v-card class="ma-4">
          <v-card-title>{{task.title}}</v-card-title>
          <v-card-text>
            <p>{{task.description}}</p>
            <p class="blue--text">{{task.status}}</p>
          </v-card-text>
          <v-card-actions>

            <v-btn
              v-if="task.status == 'Active'"
              @click="onChangeStatus(task.id, 'Completed')"
            >
              Complete Task
            </v-btn>

            <v-btn
              v-if="task.status == 'Completed'"
              @click="onChangeStatus(task.id, 'Active')"
            >
              Incomplete Task
            </v-btn>

            <v-btn
                v-if="task.status == 'Active'"
              @click="onChangeStatus(task.id, 'Postponed')"
            >
              Postpone Task
            </v-btn>

            <v-btn
              v-if="task.status == 'Postponed'"
              @click="onChangeStatus(task.id, 'Active')"
            >
              Activate Task
            </v-btn>

          </v-card-actions>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import { mapState } from 'vuex'

export default {
  async fetch({store, route}) {
    await store.dispatch('tasks/getMyTasks', {
      sid: route.params.sid
    })
  },
  methods: {
    onChangeStatus(taskId, status) {
      this.$store.commit('tasks/changeTaskStatus', {
        taskId: taskId,
        status: status,
      })
    }
  },
  computed: {
    ...mapState({
      myTasks: state => state.tasks.myTasks
    })
  }
}

My store namespaced 'tasks':

export const store = () => ({
  myTasks: []
})

export const mutations = {
  setMyTasks: (state, tasks) => {
    state.myTasks = tasks
  },
  changeTaskStatus: (state, params) => {
    let index = state.myTasks.findIndex(el => {
      return el.id == params.taskId
    })
    state.myTasks[index].status = params.status
  }
}

export const actions = {
  async getMyTasks (vuexContext, params) {
    try {
      let {data} = await this.$axios.$get('/tasks.json')
      vuexContext.commit('setMyTasks', data)
    } catch (e) {
      console.log(e)
    }
  }
}

I don't really want to have to reload the page every time a user lands on it as this defeats the purpose of SSR and SPAs.

IF YOU CAN PICK YOUR BRAIN please checkout the repo on Github and follow the steps above: https://github.com/BarryJamez/not-so-reactive-app.git

Upvotes: 1

Views: 1916

Answers (1)

Aldarund
Aldarund

Reputation: 17621

You are not defining state in your task store. In store/tasks.js

export const store = () => ({
  myTasks: []
})

while it should be

export const state = () => ({
  myTasks: []
})

Upvotes: 1

Related Questions