Как исправить ошибку "v-model cannot be used on a prop"?

Рейтинг: 1Ответов: 2Опубликовано: 07.02.2023

Пытаюсь сделать выпадающую сортировку и вылезает такая ошибка:

VueCompilerError: v-model cannot be used on a prop, because local prop bindings are not writable. Use a v-bind binding combined with a v-on listener that emits update:x event instead.

введите сюда описание изображения

<template>
<!-- Компонент App -->
  <div class="app">
    <h1>Страница с постами</h1>
    <div class="app__btns">
      <my-button @click="showDialog">Cоздать пост</my-button>
      <my-select v-model="selectedSort" :options="sortOptions" />
    </div>
    <my-dialog v-model:show="dialogVisible">
      <post-form @create="createPost" />
    </my-dialog>
    <post-list :posts="posts" @remove="removePost" v-if="!isPostsLoading" />
    <div v-else>Идет загрузка...</div>
  </div>
</template>

<script>
import axios from 'axios'
import PostForm from './components/PostForm.vue'
import PostList from './components/PostList.vue'
export default {
  components: { PostList, PostForm },
  data() {
    return {
      posts: [],
      dialogVisible: false,
      isPostsLoading: false,
      selectedSort: '',
      sortOptions: [
        { value: 'title', name: 'По названию' },
        { value: 'body', name: 'По содержанию' },
      ],
    }
  },
  methods: {
    createPost(post) {
      this.posts.push(post)
      this.dialogVisible = false
    },
    removePost(post) {
      this.posts = this.posts.filter((p) => p.id !== post.id)
    },
    showDialog() {
      this.dialogVisible = true
    },
    async fetchPosts() {
      try {
        this.isPostsLoading = true
        const res = await axios.get(
          'https://jsonplaceholder.typicode.com/posts?_limit=10'
        )
        this.posts = res.data
      } catch (error) {
        alert('ошибка')
      } finally {
        this.isPostsLoading = false
      }
    },
  },

  mounted() {
    this.fetchPosts()
  },
}
</script>

<!-- флаг scoped - значит, что стили будут применяться только к этому комопненту -->
<style>
.app {
  padding: 20px;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.app__btns {
  margin: 15px 0;
  display: flex;
  justify-content: space-between;
}
</style>
<template>
 <!-- Компонент MySelect -->
  <select v-model="modelValue" @change="changeOption">
    <option disabled value="">Выберите из списка</option>
    <option v-for="option in options" :key="option.value" :value="option.value">
      {{ option.name }}
    </option>
  </select>
</template>

<script>
export default {
  name: 'my-select',
  props: {
    modelValue: {
      type: String,
    },
    options: {
      type: Array,
      default: () => [],
    },
  },

  methods: {
    changeOption(event) {
      this.$emit('update:modelValue', event.target.value)
    },
  },
}
</script>

<style lang="scss" scoped></style>

Ответы

▲ 2Принят

Думаю уже слишком поздно, но...

v-model имеет "Односторонний поток данных", поэтому если в родителе мы использовали v-model="someDataValue", то в ребенке мы не может использовать - v-model="modelValue".

Потому что - modelValue это props и его нельзя "изменить" а можно только "прочитать"

В ребенке надо использовать :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"

(проще говоря меняем v-model="modelValue" на :value="modelValue")

И тогда - someDataValue в родителе будет изменяться.

Аналогичный вопрос на stackoverflow

▲ 2

Привет, делаю тоже это задание Мне помогло вот такое решение, вместо v-model :value