vuejs3parent-childvue-composition-apirerendercomposable

How to re-render parent component on certain event in child component in vue 3 using composition API


I can do it actually using option API, but now I'm using composition API with composables and I'm stuck. Have searched online all day but got no answer. So, I have two components (members.vue and memberStore.vue). My goal is when I post a new member in memberStore.vue (which I load in members.vue), the member list in that parent component should be automatically re-rendered.

here are those pages:

members.vue

    <template>
     <div>
      <memberStore></memberStore>
       <table >
        <thead>
          <tr>
           <th><span>Name</span></th>
           <th><span>Address</span></th>
           <th ></th>
          </tr>
         </thead>

       <tbody >
        <template v-for="item in members" :key="item.id">
         <tr>
           <td> {{ item.name }} </td>
           <td> {{ item.address }} </td>
         </tr>
        </template>
      </tbody>
    </table>
  </div>
</template>

<script>
 import useMembers from "../../composables/members";
 import { onMounted } from "vue";
 import memberStore from "../../components/members/memberStore.vue";
 export default {
    components: { memberStore },
   setup() {
   const { members, getMembers } = useMembers();

   onMounted(getMembers);

   return {
     members,
   };
   },
 };
</script>   

memberStore.vue

   <template>
    <div> 
        <form @submit.prevent="saveMember">
            <div>
                
                <div><label for="name" >Name</label></div>
                    <div > <input type="text" name="name" id="name" v-model="form.name" >  </div>
                <div> <label for="address">Address</label > </div>
                    <div><input type="text" name="address" id="address" v-model="form.address" ></div>
            </div>
          <div>
            <button type="submit" > Save</button>
          </div>
        </form>
      </div>
    </template>

    <script>
    import { reactive } from "vue";
    import useMembers from "../../composables/members";
    export default {
        setup() {
        const form = reactive({
            name: "",
            address: "",
        });
    
        const { errors, storeMember } = useMembers();
    
        const saveMember = async () => {
            await storeMember({ ...form });
        };
    
        return {
            form,
            errors,
            saveMember,
        };
        },
    };
    </script>

src/composables/members.js

   import { ref } from "vue";
   import axios from "axios";
   import { useRouter } from "vue-router";
   import axiosClient from "../axios";

   export default function useMembers() {
    const members = ref([]);
    const member = ref([]);
    const router = useRouter();
    const errors = ref("");

    const getMembers = async () => {
      let response = await axiosClient.get("/members");
      members.value = response.data.data;
    };

   const getMember = async (id) => {
     let response = await axiosClient.get("/members/" + id);
     member.value = response.data.data;
   };

   const storeMember = async (data) => {
     errors.value = "";
     try {
        await axiosClient.post("/members", data);
     } catch (e) {
       if (e.response.status === 422) {
          errors.value = e.error.response.data;
       }
     }
   };

    return {
     members,
     getMembers,
     router,
     member,
     getMember,
     storeMember,
   };
 }

All of these are working as I expected. The only problem is I can't find a way to auto re-render the parent component


Solution

  • I solved it using emit event

    In memberStore.vue I added the following:

    script

    emits: ["customChange"],
    setup(props, context) {
    ...
    const handleChange = () => {
      context.emit("customChange");
    };
    return {
      .... 
      handleChange,
     }; 
    }
    

    trigger

    <form @submit.prevent="saveMember" @submit="handleChange">
    

    members.vue

     <memberStore @customChange="getmembers"></memberStore>