Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

boyjarv's avatar

Unexpected mutation of Prop

Please help, I get:

error Unexpected mutation of "pagination" prop vue/no-mutating-props

I am following a similar style to what is done here: https://github.com/sm-jahangir/essential-laravel-vuejs/blob/master/resources/js/components/partials/PaginationComponent.vue

Pease help

here is my PaginateItems component:

<template>
  <nav aria-label="...">
    <ul class="pagination justify-content-center">
      <li class="page-item" :class="{ disabled: pagination.current_page <= 1 }">
        <a class="page-link" @click.prevent="changePage(1)">First page</a>
      </li>
      <li class="page-item" :class="{ disabled: pagination.current_page <= 1 }">
        <a
          class="page-link"
          @click.prevent="changePage(pagination.current_page - 1)"
          >Previous</a
        >
      </li>

      <li
        class="page-item"
        v-for="page in pages"
        :key="page"
        :class="isCurrentPage(page) ? 'active' : ''"
      >
        <a class="page-link" @click.prevent="changePage(page)"
          >{{ page }}
          <span v-if="isCurrentPage(page)" class="sr-only">(current)</span>
        </a>
      </li>

      <li
        class="page-item"
        :class="{ disabled: pagination.current_page >= pagination.last_page }"
      >
        <a
          class="page-link"
          @click.prevent="changePage(pagination.current_page + 1)"
          >Next</a
        >
      </li>
      <li
        class="page-item"
        :class="{ disabled: pagination.current_page >= pagination.last_page }"
      >
        <a class="page-link" @click.prevent="changePage(pagination.last_page)"
          >Last page</a
        >
      </li>
    </ul>
  </nav>
</template>

<script>
export default {
  props: ["pagination", "offset"],
  methods: {
    isCurrentPage(page) {
      return this.pagination.current_page === page;
    },
    changePage(page) {
      if (page > this.pagination.last_page) {
        page = this.pagination.last_page;
      }
      this.pagination.current_page = page;
      this.$emit("paginate");
    },
  },
  computed: {
    pages() {
      let pages = [];
      let from = this.pagination.current_page - Math.floor(this.offset / 2);
      if (from < 1) {
        from = 1;
      }
      let to = from + this.offset - 1;
      if (to > this.pagination.last_page) {
        to = this.pagination.last_page;
      }
      while (from <= to) {
        pages.push(from);
        from++;
      }
      return pages;
    },
  },
};
</script>

and here is my contactView.vue

<template>
  <NavBar />
  <div :class="{ 'is-loading': isLoading }">&nbsp;</div>
  <div v-if="!isLoading" class="container max-w-6xl mx-auto my-20">
    <div class="flex justify-between mx-8 md:mx-4 mb-4">
      <h2 v-show="!isLoading" class="text-2xl text-center">Contacts</h2>
      <AppButton
        type="secondary"
        :processing="isLoading"
        @click.prevent="isOpen = true"
      >
        Add New Contact
      </AppButton>
    </div>
    <ListItems :listItems="contacts" type="contact" />
    {{ links }}
    <PaginateItems
      v-if="pagination.last_page > 1"
      :pagination="pagination"
      :offset="5"
      @paginate="query === '' ? getAllContacts() : searchData()"
    ></PaginateItems>
    <ModalWindow :open="isOpen" @close="this.isOpen = !this.isOpen">
      <AddEditForm />
    </ModalWindow>
  </div>
</template>

<script>
import { ref } from "vue";
import AppButton from "@/components/AppButton.vue";
import axios from "axios";
import NavBar from "@/components/NavBar.vue";
import ListItems from "@/components/ListItems.vue";
import PaginateItems from "@/components/PaginateItems.vue";
import ModalWindow from "@/components/ModalWindow.vue";
import AddEditForm from "@/components/contact/AddEditForm.vue";
export default {
  name: "ContactPage",
  components: {
    AppButton,
    NavBar,
    ListItems,
    PaginateItems,
    ModalWindow,
    AddEditForm,
  },
  data() {
    return {
      isLoading: false,
      contacts: [],
      links: [],
      isOpen: ref(false),
      pagination: {
        current_page: 1,
      },
    };
  },
  methods: {
    async getAllContacts(pageNo = 1) {
      this.isLoading = true;
      let response = await axios.get(
        `https://apiendpoint?page=${pageNo}`
      );
      try {
        this.contacts = response.data.data;
        this.links = response.data.links;
        this.pagination = response.data.meta;
        this.isLoading = false;
      } catch (error) {
        console.log("Error: ", error);
      }
    },
  },
  mounted() {
    this.getAllContacts();
  },
};
</script>
0 likes
12 replies
vincent15000's avatar

Props are not made for being changed, it's just a way to pass parameters to your view.

If you need to change the props value inside your code, you need to create a data and assign the props value to the data. Then you will be able to change the data value.

vincent15000's avatar

@boyjarv No it's not exactly the same code.

In the code on github, the code never tries to change the value of the pagination variable. In your code, you try to change it.

this.pagination = response.data.meta;
vincent15000's avatar

@boyjarv I just noticed that the code on github tries to change a property of the pagination object.

this.pagination.current_page = page;

I don't know what type of error it can generate.

Sinnbeck's avatar

@boyjarv please remember to mark a best answer to set the thread as solved

1 like
MohamedTammam's avatar
Level 51

The error in that line

this.pagination.current_page = page;

the pagination is a prop and you're mutating/changing it.

Don't do that, just emit an event and let the parent component update it.

1 like
boyjarv's avatar

@MohamedTammam I know you can't mutate props. I gave up on this in the end and reverted to using a pagination package

2 likes

Please or to participate in this conversation.