1

I am trying to edit a post using state manager vuex, in vue3 using compostion API and here is my code:

<template>
  <div class="container py-5">
    <h3 class="mb-5 border-top-0 border-start-0 border-end-0 pb-3 border">
      Edit Post
    </h3>
    <div v-if="formData.loading">
      <div class="spinner-border text-primary" role="status"></div>
    </div>
    <form v-else @submit.prevent="validation">
      <div class="form col-md-7">
        <div class="mb-3">
          <label for="title" class="form-label">Title</label>
          <input
            v-model="formData.title"
            type="text"
            class="form-control"
            @input="formData.titleErr = false"
            id="title"
            placeholder="Please inter the title"
          />
          <p class="my-2 text-danger" v-if="formData.titleErr">
            This title is not valid
          </p>
        </div>
        <div class="mb-3">
          <label for="content" class="form-label">content</label>
          <textarea
            class="form-control"
            id="content"
            placeholder="Please enter the context"
            rows="7"
            v-model="formData.content"
            @input="formData.contentErr = false"
          ></textarea>
          <p class="my-2 text-danger" v-if="formData.contentErr">
            This content is not valid
          </p>
        </div>
        <button
          type="submit"
          value=""
          class="btn btn-primary"
          @click="validation">
          Edit
        </button>
      </div>
    </form>
  </div>
</template>

And here is the script

<script>
import { computed, onMounted, reactive } from "vue";
import { useStore } from "vuex";
import { useRoute } from "vue-router";    
export default {
  setup() {
    const store = useStore();
    const formData = reactive({
      title: "",
      titleErr: false,
      invalidTitle: true,
      content: "",
      contentErr: false,
      invalidContent: true,
      loading: false,
    });
    const route = useRoute();  
    const postInfo = computed(() => store.getters["postsModule/setSinglePost"]);
    onMounted(() => {
      formData.title = postInfo.value.title;
      formData.content = postInfo.value.body;
    });
    const validation = () => {
      if (formData.title === "" && formData.invalidTitle) {
        formData.titleErr = true;
      } else {
        formData.invalidTitle = !formData.invalidTitle;
        formData.titleErr = false;
      }
      if (formData.content === "" && formData.invalidContent) {
        formData.contentErr = true;
      } else {
        formData.invalidContent = !formData.invalidContent;
        formData.contentErr = false;
      }
      if (
        formData.title !== "" &&
        !formData.invalidTitle &&
        formData.content !== "" &&
        !formData.invalidContent
      ) {
        const data = {
          title: formData.title,
          body: formData.content,
        };
        editPost(data);
      }
      formData.title = "";
      formData.content = "";
    };
    return { formData, validation, postInfo };
  },
};
</script>

The problem is that I need the value of postInfo which is taken from the store, however, the data is not updated correctly. The first time the page is rendered, all the inputs are empty, the other times the data is related to the last rendered time. maybe the problem is that the computed value is not envoked when the first render happened because setup is not returned any thing yet.

by the way here is the store

import axios from "axios";
import Swal from "sweetalert2";

const postsModule = {
  namespaced: true,
  state: {
    posts: [],
    singlePost: {},
  },
  getters: {
    setPosts(state) {
      return state.posts;
    },
    setSinglePost(state) {
      return state.singlePost;
    },
  },
  mutations: {
    getPosts(state, posts) {
      return (state.posts = posts);
    },
    getSingle(state, post) {
      return (state.singlePost = post);
    },
  },
  actions: {
    // get post list
    async fetchPosts({ commit }) {
      const res = await axios.get(`http://localhost:3004/posts`);
      const data = res.data;
      commit("getPosts", data);
    },
    // view each post
    async fetchSinglePost({ commit }, id) {
      const res = await axios.get(`http://localhost:3004/posts/${id}`);
      commit("getSingle", res.data);
    },
    //  delete single post
    async deleteSinglePost({ commit }, id) {
      const res = await axios.delete(`http://localhost:3004/posts/${id}`);
      commit("updateAfterDelete", res.data);
    },
    // create post
    async createSinglePost(context, newPostData) {
      await axios.post(`http://localhost:3004/posts`, newPostData);
      Swal.fire({
        title: "Thanks!",
        text: "submission is done",
        icon: "success",
        confirmButtonText: "Cool",
      });
    },
  },
};
export default postsModule;

Is there any solution for it to sync the computed value correctly through any render? I mean when the first component is rendered the inputs values are not empty.

sara
  • 21
  • 3

1 Answers1

0

Since you're using async calls in your setup, you can change the setup to an async setup and then await those inner async calls to make sure the data is loaded before you return it to your template. Just make sure to use a Suspense tag in the parent component. Here is a good post explaining the solution, Why did I get blank (empty) content when I used async setup() in Vue.js 3?

vhud
  • 1
  • 1