Vue3 - Issues adressing attributes from ProxyObjects returned from Vuex´ store

43 Views Asked by At

Repository: https://github.com/ElTruHTML/vocabtrainer_vue

Within a part of my TopicCardES.vue Component i use a computed method to show an object:
TopicCardES.vue/template:
<p>{{ topicName }}</p>
TopicCardES.vue/script/computed:

topicName() {
            return this.$store.getters.getTopicArray[this.$store.getters.tIndex];
        }

This is the result: shows object
This result is shown without any issues, even after refreshing page. Now i actually wanted to only show the name of this topic. But i encountered a lot of issues.If i edit the computedMethod like that:
TopicCardES.vue/script/computed(only name):

topicName() {
            return this.$store.getters.getTopicArray[this.$store.getters.tIndex].name;
        }

it is shown as expected:only_name
But if the user refreshes the site accidently i get this error:
error The interesting part is the following: what you see is rendered on the route "/dashboard/editsets". You reach this particular window by clikcing on a <button @click="$router.push("'/dashboard/editsets')". The name is displayed correctly. If i refresh, this error occurs, but even if i go back to /dashboard and click this button again.

Now i learned that after refreshing, app instance is destroyed an rebuild, what also destroys the state. But considering my specific problem i have two questions:

  1. Why doesnt Vue have a problem with refreshing while displaying the complete object?
  2. I managed so set the state after every reload of the page using beforeMount() hook, so there shouldnt be a problem finding the name but why is it still there?

This is the hierarchy of the relevant components:

TopicCardES.vue --(used by)--> TopiccardWrapper.vue --(used by)--> TheEditsets.vue

Because Editsets is the biggest parentComponent of the route "/dashboard/editsets" the setting and fetching from store happens here. Here is its script. The part where all topics of the currently logged in user are fetched happens at the end of "beforeMount(), starting with let allStats
TheEditsets.vue/script:

    computed: {
        getTotalTopics() {
            return this.$store.state.USER_INFO_totaltopics;
        }
    },
    async beforeMount() {
        console.clear();
        console.log(this.$store.state);
        let initial_logincheck = await this.$store.dispatch("checkUserLogged");
        if(initial_logincheck.success) {
            this.$store.commit("login", initial_logincheck.logged_user);
            this.loggedUserName = initial_logincheck.logged_user;
        }
        else {
            console.error("USER NICHT EINGELOGGT!");
            this.$router.push("/");
        }

        if(this.$store.getters.getLoggedState)
        {
            await this.getTotals();
        }

        let allStats = await this.$store.dispatch("post", {task: "fetch_all_topic_stats"});
        this.$store.commit("setTopicStats", allStats);
        console.log(this.$store.state);
    },
    methods: {
        async getTotals() {
            let totalsrequest = {task: "get_totals"};
            let totalresult = await this.$store.dispatch("post", totalsrequest);
            if(totalresult.success) {
                this.$store.commit("setTotals", totalresult);
                this.totalTopics = totalresult.totalTopics;
                this.totalVocabs = totalresult.totalVocabs;
            }
            else {
                console.error("TOTALS NICHT GEHOLT!");
            }
        },
    },

As you can see, the fetched Array containg the topics is used to set those values into the store using the mutation setTopicStats. Thas why i give you the store now:
main.js/createStore:

    state() {
        return {
            API                     : "http://localhost/vue_projects/vocabtrainer/backend/main.php",
            LOG_INFO_islogged       : false,
            LOG_INFO_name           : null,
            USER_INFO_totaltopics   : null,
            USER_INFO_totalvocabs   : null,
            USER_topicArray         : [],
            USER_tIdx               : 0,
        };
    },
    mutations: {
        logout(state) {
            state.LOG_INFO_islogged     = false;
            state.LOG_INFO_name         = null;
            state.USER_INFO_totaltopics = null;
            state.USER_INFO_totalvocabs = null;
            router.push("/");
        },
        login(state, username) {
            state.LOG_INFO_islogged = true;
            state.LOG_INFO_name = username;
        },
        setTotals(state, result) {
            state.USER_INFO_totaltopics = result.totalTopics;
            state.USER_INFO_totalvocabs = result.totalVocabs;
        },
        setTopicStats(state, fetchedTopics) {
            state.USER_topicArray = [...fetchedTopics.topics];
        },
    },
    getters: {
        tIndex(state) {
            return state.USER_tIdx;
        },
        getTopicArray(state) {
            return state.USER_topicArray;
        },
        getLoggedState(state) {
            return state.LOG_INFO_islogged;
        },
        getLoggedUsernameState(state) {
            return state.LOG_INFO_name;
        },
        getTopicsCountState(state) {
            return state.USER_INFO_totaltopics;
        },
        getVocabsCountState(state) {
            return state.USER_INFO_totalvocabs;
        },
    },

Now that you have the code from editsets and the store, lets go downside along the hiarchy. After Editsets.vue comes TopiccardWrapper.vue. It does not have any script. It uses the TopicCardES.vue within the template:
<topic-card-es></topic-card-es>

An the relevant parts of TopiccardWrapper.vue are already shown.

Now how come that vue seems to "forget" that the object has an attribute "name" but never forgets the object itself (containing the attribute "name")?

EDIT: Because i got that said a few times: the way the complete object is shown seems like its a JSON-String, thats what i thought too(allthough it shouldnt be) trying JSON.parse did NOT do the trick. And its also not possible to be a JSON String because for every backend fetch i use the method "post" thats in the "actions" of my store. And withing this "post"-method all the data from the backend are converted into JS Objects with response.json(). Here it is:
main.js/createStore/actions:

async post(context, dataobject) {
          let summary = {};
          let req = undefined;
          if(dataobject)
          {
              req = {
                  method: "post",
                  body: JSON.stringify(dataobject),
                  credentials: "include",
                  headers: {
                      "Content-Type": "application/json",
                  },
              };
              //###############################################
              let response = await fetch(context.state.API, req);
              //###############################################
              if(!response.ok) {
                  setTimeout(() => {
                    console.error("IRGENDEIN FEHLER MIT DER REQUEST");
                    //   location.href = "./sites/error.html";
                  }, 1000);
              } else {
                  let resolvedResponse = await response.json();
                  resolvedResponse.success === true ?
                  summary.success = true :
                  summary.success = false;
                  if(!summary.success) {
                    //some errorhandling...
                  }
                  switch(dataobject.task) {
                    case "login_user":
                    case "is_a_user_logged":
                      summary.logged_user = resolvedResponse.logged_user;
                      break;
                    case "get_totals":
                        summary.totalTopics = resolvedResponse.totalTopics;
                        summary.totalVocabs = resolvedResponse.totalVocabs;
                        break;
                    case "fetch_all_topic_stats":
                        summary.topics = resolvedResponse.allTopics;
                        break;
                    default:
                      break;
                  }
              }
          }
          return summary;
        },
0

There are 0 best solutions below