4

I'm new to vue and I was trying to change one of my components in to the new syntax to learn vue 3. The component was working just fine before the change so I must be missing something.

this is the mother component:

<template>
  <div class="user-profile">
    <div>
      <div class="user-profile__user-panel">
        <h1 class="user-profile__username">@{{ user.username }}</h1>
        <div v-if="user.isAdmin" class="user-profile__admin-badge">Admin</div>
        <div class="user-profile__follower-count">
          <string><b>Followers: </b></string> {{ followers }}
        </div>
      </div>
      <NewTwoot @create-twoot="createNewTwoot" />
    </div>
    <div class="user-profile__twoots-wraper">
      <TwootItem
        v-for="twoot in user.twoots"
        :username="user.username"
        :key="twoot.id"
        :twoot="twoot"
        @favorit="toggleFavorite(id)"
      />
    </div>
  </div>
</template>

<script>
import TwootItem from "./TwootItem.vue";

export default {
  name: "UserProfile",
  components: {
    TwootItem,
  },
  data() {
    return {
      followers: 0,
      user: {
        id: 1,
        username: "GabrielBG",
        firstName: "Gabriel",
        lastName: "Gutierrez",
        email: "gbg@scienceiscoll.com",
        isAdmin: true,
        twoots: [
          {
            id: 2,
            content: "This is my second twoot",
          },
          {
            id: 3,
            content: "This is my third twoot",
          },
          {
            id: 1,
            content: "This is my first twoot",
          },
        ],
      },
    };
  },
  watch: {
    followers(newFollowerCount, oldFollowerCount) {
      if (oldFollowerCount > newFollowerCount) {
        console.log("You lost a follower!");
      } else {
        console.log("You gained a follower!");
      }
    },
  },
  computed: {
    fullName() {
      return this.user.firstName + " " + this.user.lastName;
    },
  },
  methods: {
    followUser() {
      this.followers++;
    },
    toggleFavorite(id) {
      console.log("Toggling favorite for twoot with id: " + id);
    },
    createNewTwoot(newTwootContent) {
      this.user.twoots.unshift({
        id: this.user.twoots.length + 1,
        content: newTwootContent,
      });
    },
  },
  mounted() {
    this.followUser();
  },
};
</script>

And this is the component that was refactored but now it does not render:

<template>
  <form class="create-twoot" @submit.prevent="createNewTwoot">
    <lable for="new-twoot"
      ><strong>New Twoot</strong> ({{ newTwootCharCount }}/180)
    </lable>
    <textarea id="new-twoot" rows="5" v-model="state.newTwootContent" />
    <div class="create-twoot-type">
      <lable for="twoot-type">
        <strong>Twoot Type</strong>
      </lable>
      <select id="twoot-type" v-model="state.selectedTwootType">
        <option
          :value="option.value"
          v-for="(option, index) in state.twootTypes"
          :key="index"
        >
          {{ option.name }}
        </option>
      </select>
    </div>
    <button
      type="submit"
      :disabled="
        newTwootContent.length === 0 ||
        newTwootContent.length > 180 ||
        newTwootType == 'draft'
      "
    >
      Twoot
    </button>
  </form>
</template>

<script>
import { reactive, computed } from "vue";
export default {
  name: "NewTwoot",
  setup(_props, ctx) {
    const state = reactive({
      newTwootContent: "",
      selectedTwootType: "instant",
      twootTypes: [
        { value: "draft", name: "Draft" },
        { value: "instant", name: "Instant Twoot" },
      ],
    });

    const newTwootCharCount = computed(() => state.newTwootContent.length);

    function createNewTwoot() {
      ctx.emit("create-twoot", state.newTwootContent);
      state.newTwootContent = "";
    }

    return {
      state,
      newTwootCharCount,
      createNewTwoot,
    };
  },
};
</script>

I can see it on the elements tree but it show up as <newtwoot></newtwoot> as if it was empty.

1 Answers1

2

I see two errors:

  1. you only import TwootItem in the parent but not NewTwoot. This explains why it is not rendered properly.
  2. You don't define the emit in the child component, look at my answer here: vue 3 emit warning " Extraneous non-emits event listeners"

So importing the missing component import NewTwoot from "./NewTwoot.vue"; and adding it to the components should do the trick:

components: {
    NewTwoot,
    TwootItem,
}
Thomas
  • 6,325
  • 4
  • 30
  • 65