Default value for props like an object didn't work

Viewed 590

I have a very strange situation :

My HomeComponent.vue

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <HelloWorld :msg="msg" @update="inputUpdated" />
  </div>
</template>

<script lang="ts">
  import { defineComponent } from "vue";
  import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
  import { Message } from "@/interfaces/message";

  export default defineComponent({
    name: "Home",
    components: {
      HelloWorld,
    },
    setup(props, { emit }) {
      const msg: Message = {
        year: 2020,
      };
      function inputUpdated(value): void {
        console.log("Get Event : " + value);
      }
      return {
        msg,
        inputUpdated,
      };
    },
  });
</script>

My HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg.title }} in the year : {{ msg.year }}</h1>
    <button @click="increment">count is : {{ count }}</button>
    <div>{{ pow(2, 3) }}</div>
    <p>Edit <code>component</code> to test state is {{ state.year }}</p>
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref, reactive, PropType } from "vue";
  import { State } from "@/interfaces/state";
  import { Message } from "@/interfaces/message";

  export default defineComponent({
    name: "HelloWorld",
    props: {
      msg: {
        type: Object as PropType<Message>,
        required: true,
        default: function () {
          return {
            title: "Arrow Function Expression",
            year: 2020,
          };
        },
      },
    },
    setup(props, { emit }) {
      console.log(props);
      const count = ref(0);
      const state: State = reactive({
        title: "",
        year: 2020,
      });
      function pow(x: number, y: number): number {
        return Math.pow(x, y);
      }

      function increment(): void {
        console.log("Emit : Hello World");
        emit("update", "Hello World");
        count.value++;
      }

      return {
        count,
        increment,
        pow,
        state,
      };
    },
  });
</script>

The interface Message :

export interface Message {
    title?: string;
    year?: number;
}

The problem what I have is even if I created a default for msg props didn't work, is not taken into account. I have the message in the year :. What I'm doing wrong with default values for props values ? Thx in advance and sorry for my english.

1 Answers

You're expecting the default prop's properties to be merged with the passed prop. That won't work and would mean the prop was modified, and props should not be modified. The default prop is used only when no prop has been passed (so you don't need the required attribute.)

You'll have to decide between splitting up the object into individual props:

props: {
  title: ...,
  year: ...
}

Or use a computed to merge:

setup(props) {
  const msgDefault = {
    title: "Arrow Function Expression",
    year: 2020,
  };
  const merged = computed(() => {
    return Object.assign({}, msgDefault, props.msg);  // shallow merge
  })
  return { merged }
}
Related