> 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.

# State & Getters

## State

State là object chứa toàn bộ dữ liệu chia sẻ, là single source of truth của store.

```js
state: {
  count: 0,
  user: null,
  cart: []
}
```

Truy cập trong component qua `this.$store.state`:

```js
computed: {
  count() {
    return this.$store.state.count
  }
}
```

State của Vuex là reactive. Component dùng state trong computed sẽ tự cập nhật khi state đổi.

## mapState

Khi cần nhiều state, viết từng computed thủ công dài dòng. `mapState` sinh computed tự động.

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

export default {
  computed: {
    ...mapState(['count', 'user']),

    // đổi tên hoặc tính toán thêm
    ...mapState({
      total: state => state.cart.length,
      userName: 'user'
    })
  }
}
```

`...mapState([...])` trộn các computed vào, dùng `this.count`, `this.user` như computed bình thường. Kết hợp với computed cục bộ bằng spread operator.

## Getters

Getter là giá trị dẫn xuất từ state, vai trò như computed nhưng ở cấp store. Có cache theo dependency, chỉ tính lại khi state phụ thuộc đổi. Dùng khi nhiều component cần cùng một logic tính toán từ state.

```js
getters: {
  completedTodos(state) {
    return state.todos.filter(t => t.done)
  },
  completedCount(state, getters) {
    // getter có thể dùng getter khác qua tham số thứ hai
    return getters.completedTodos.length
  }
}
```

Truy cập qua `this.$store.getters`:

```js
computed: {
  done() {
    return this.$store.getters.completedTodos
  }
}
```

### Method-style getter

Getter trả về function để nhận tham số. Dạng này không cache (chạy mỗi lần gọi).

```js
getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(t => t.id === id)
  }
}
```

```js
this.$store.getters.getTodoById(2)
```

## mapGetters

Trộn getter vào computed tương tự mapState.

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

export default {
  computed: {
    ...mapGetters(['completedTodos', 'completedCount']),

    // đổi tên
    ...mapGetters({
      doneList: 'completedTodos'
    })
  }
}
```

## State vs Getter

|          | State         | Getter                                       |
| -------- | ------------- | -------------------------------------------- |
| Bản chất | Dữ liệu gốc   | Giá trị tính từ state                        |
| Cache    | Reactive      | Có cache như computed                        |
| Khi dùng | Đọc trực tiếp | Cần lọc/biến đổi/tổng hợp dùng lại nhiều nơi |

## Tips cho AEM

Khởi tạo state ban đầu từ dữ liệu server-side. Sling Model serialize JSON, clientlib parse và đưa vào state khi tạo store, các component đọc qua getter.

```js
const initial = JSON.parse(
  document.getElementById('app-state')?.dataset.state || '{}'
)

const store = new Vuex.Store({
  state: {
    user: initial.user || null,
    locale: initial.locale || 'vi'
  },
  getters: {
    isLoggedIn: state => !!state.user
  }
})
```
