Cùng tiếp tục với Bài 22 – Quản lý trạng thái người dùng với useState()
và composables trong NuxtJS. Đây là phần quan trọng để làm ứng dụng có trạng thái đăng nhập rõ ràng, dễ dùng, tái sử dụng nhiều lần ở mọi nơi trong project.
1. Vấn đề: dùng useCookie()
rải rác
Nếu bạn dùng useCookie()
ở nhiều nơi để đọc auth_token
, user
, role
→ code rối, khó bảo trì.
Giải pháp: Tạo một composable useAuth()
để tập trung xử lý user login.
2. Sử dụng useState()
– tạo state dùng lại toàn app
Trong Nuxt, useState()
là cách tạo biến global, reactive và auto SSR/CSR.
Ví dụ:
const user = useState('user', () => null)
const token = useState('token', () => null)
→ Bạn có thể truy cập từ bất kỳ component nào.
3. Tạo composable useAuth()
Tạo file: composables/useAuth.ts
export const useAuth = () => {
const user = useState('user', () => null)
const token = useState('token', () => null)
const role = useState('role', () => null)
const login = async (email: string, password: string) => {
try {
const res = await $fetch('/api/login', {
method: 'POST',
body: { email, password }
})
token.value = res.token
user.value = res.user
role.value = res.user?.role || 'user'
// Lưu vào cookie
useCookie('auth_token').value = res.token
useCookie('user').value = res.user
useCookie('user_role').value = res.user.role
} catch (err) {
throw new Error('Đăng nhập thất bại')
}
}
const logout = () => {
token.value = null
user.value = null
role.value = null
useCookie('auth_token').value = null
useCookie('user').value = null
useCookie('user_role').value = null
}
return { user, token, role, login, logout }
}
4. Dùng useAuth()
trong login page
<script setup>
const email = ref('')
const password = ref('')
const error = ref('')
const { login } = useAuth()
const router = useRouter()
async function submit() {
try {
await login(email.value, password.value)
router.push('/dashboard')
} catch (e) {
error.value = e.message
}
}
</script>
5. Dùng useAuth()
ở header, layout, component
Ví dụ trong components/Header.vue
:
<script setup>
const { user, logout } = useAuth()
</script>
<template>
<div>
<span v-if="user">Xin chào, {{ user.name }}</span>
<button v-if="user" @click="logout">Đăng xuất</button>
</div>
</template>
→ Khi logout, toàn bộ giao diện tự reactive theo.
6. Đồng bộ cookie
vào state khi trang load
Tạo file plugins/init-auth.ts
:
export default defineNuxtPlugin(() => {
const token = useCookie('auth_token').value
const user = useCookie('user').value
const role = useCookie('user_role').value
useState('token', () => token)
useState('user', () => user)
useState('role', () => role)
})
→ Khi user F5, Nuxt đọc cookie và phục hồi state → không bị mất trạng thái login.
7. Gợi ý mở rộng
isLoggedIn = computed(() => !!token.value)
isAdmin = computed(() => role.value === 'admin')
isEditor = computed(() => ['admin', 'editor'].includes(role.value))
Bạn có thể thêm vào useAuth()
để sử dụng tiện lợi.
Bạn đã học được
- Tạo state toàn cục bằng
useState()
- Gom login/logout vào composable
useAuth()
- Dùng lại
useAuth()
ở bất kỳ đâu trong app - Tự đồng bộ cookie vào state bằng plugin
- Tái sử dụng và mở rộng rất linh hoạt
Bài tập mở rộng
- Tạo nút
Đăng xuất
ở layout - Hiển thị tên người dùng ở header nếu đã login
- Nếu chưa login → ẩn menu admin
- Gắn
isLoggedIn
,isAdmin
,isEditor
vàouseAuth()
Thảo luận