'Vue 3 Composition API: Update Child components props dynamically when values update from the parent component

I am trying to update a prop value when the data from the parent component gets updated and passes through the prop. The parent value always updates but does not update or re-renders in the child component when I pass it down. It passes to the prop the first time the child component is accessed but not when the data is updated in the parent component.

Below is the parent component:

<script setup>
import { inject, watchEffect, ref } from "vue";
import ChildComponent from "@/components/ChildComponent.vue"
const { state } = inject("store");
const cart = ref(state.cart);

watchEffect(() => (cart.value = state.cart));

</script>
<template>
  <ChildComponent
   v-for="(item, index) in cart?.items"
   :key="index"
   :cartItem="item"
  />
</template>

Below is the child component (only logs on the first load, never loads again):

<script setup>
import { ref, watchEffect } from "vue";

const { cartItem } = defineProps({
  cartItem: !Object
});

const item = ref(cartItem);

watchEffect(() => {
  console.log(item.value)
});
    
</script>

I have tried using Watch in many ways but it does not detect the old or the new values. It does not log any outputs

Example child component using watch:

<script setup>
import { ref, watch } from "vue";

const { cartItem } = defineProps({
  cartItem: !Object
});

const item = ref(cartItem);

watch(() => item.value, (oldValue, newValue) => {
  console.log(oldValue)
  console.log(newValue)
});
        
</script>


Solution 1:[1]

I ended up solving the solution by using a v-if to rerender the child component.

<script setup>
import { inject, watchEffect, ref } from "vue";
import ChildComponent from "@/components/ChildComponent.vue"
const { state } = inject("store");
const cart = ref(state.cart);
const render = ref(true);

// Checks when the cart changes from the store
watchEffect(() => {
  if(cart.value) {
    render.value = true
  }
  else {
    render.value = true
  }
};

</script>
<template>
<div v-if="render">
  <ChildComponent
   v-for="(item, index) in cart?.items"
   :key="index"
   :cartItem="item"
  />
</div>
</template>

Solution 2:[2]

I had the same issue and it was frustrating, sometimes I had to do a workaround to get what I need, but try this inside the child component:

<script>
import { ref, watch } from "vue";

export default {
props: {
 cartItem: {
  type: !Object,
 },
},

setup(props) {
 const item = ref(null);

 watch(props, () => {
  item.value = props.cartItem;
 });

 return { item }
}
</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Sexwale
Solution 2