> For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt.

# Mutations

Mutation là cách duy nhất được phép thay đổi state trong Vuex. Mỗi mutation là một hàm nhận `state` và đổi state trực tiếp. Gọi mutation bằng `commit`.

## Định nghĩa và commit

```js
mutations: {
  increment(state) {
    state.count++
  }
}
```

```js
this.$store.commit('increment')
```

## Payload

Truyền dữ liệu kèm theo qua tham số thứ hai. Quy ước dùng một object để rõ ràng.

```js
mutations: {
  incrementBy(state, payload) {
    state.count += payload.amount
  }
}
```

```js
this.$store.commit('incrementBy', { amount: 10 })

// hoặc object-style commit
this.$store.commit({
  type: 'incrementBy',
  amount: 10
})
```

## Mutation phải đồng bộ

Đây là quy tắc quan trọng nhất. Mutation phải đồng bộ (synchronous). Không đặt callback bất đồng bộ (setTimeout, fetch) bên trong mutation, vì devtools không thể track đúng thời điểm state đổi, gây khó debug.

```js
// SAI: thao tác async trong mutation
mutations: {
  loadData(state) {
    fetch('/api/data').then(res => {
      state.data = res // không track được
    })
  }
}
```

Logic bất đồng bộ phải đặt trong action, action gọi fetch xong rồi commit mutation (xem note Actions).

## Reactivity caveats

Vuex state dùng cùng hệ reactivity của Vue 2 nên có cùng hạn chế. Thêm property mới vào object hoặc gán phần tử theo index sẽ không reactive.

```js
mutations: {
  // SAI: thêm key mới không reactive
  addField(state) {
    state.user.age = 30
  },

  // ĐÚNG: dùng Vue.set
  addField(state) {
    Vue.set(state.user, 'age', 30)
  },

  // ĐÚNG: thay cả object để giữ reactive
  setUser(state, user) {
    state.user = { ...state.user, ...user }
  }
}
```

Với mảng, dùng các method reactive (`push`, `splice`) hoặc gán lại mảng mới.

## mapMutations

Trộn việc commit thành methods của component.

```js
import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations(['increment', 'incrementBy']),

    // đổi tên
    ...mapMutations({
      add: 'increment'
    })
  }
}
```

```html
<button @click="increment">+1</button>
<button @click="incrementBy({ amount: 5 })">+5</button>
```

## Đặt tên mutation

Quy ước dùng hằng số cho tên mutation trong project lớn để tránh gõ sai chuỗi và dễ tra cứu.

```js
// mutation-types.js
export const INCREMENT = 'INCREMENT'
```

```js
import { INCREMENT } from './mutation-types'

mutations: {
  [INCREMENT](state) {
    state.count++
  }
}
```

## Tips cho AEM

Mutation nên nhỏ và đơn nhiệm: chỉ gán state. Khi nhận dữ liệu từ API trong AEM (vd gọi Sling Servlet), action lo gọi và xử lý, mutation chỉ lưu kết quả.

```js
mutations: {
  setProducts(state, products) {
    state.products = products
  },
  setLoading(state, value) {
    state.loading = value
  }
}
```
