Skip to content

Commit b25eb95

Browse files
committed
fix: composables are initialized on mount
Defers initialization of authentication and user composables until the component is mounted to prevent potential issues with SSR and component lifecycle. This change also ensures composables are accessed safely using computed properties, providing default values when the composable is not yet initialized. This addresses potential errors related to accessing reactive properties before they are available.
1 parent 58dc7a3 commit b25eb95

File tree

4 files changed

+62
-20
lines changed

4 files changed

+62
-20
lines changed

src/runtime/components/NUsersList.vue

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { onMounted } from 'vue'
2+
import { onMounted, computed } from 'vue'
33
import { useUsers } from '../composables/useUsers'
44
import { defaultDisplayFields, defaultFieldLabels, type User } from 'nuxt-users/utils'
55
@@ -19,26 +19,37 @@ const emit = defineEmits<{
1919
(e: 'editClick' | 'delete', user: User): void
2020
}>()
2121
22-
const {
23-
users,
24-
pagination,
25-
loading,
26-
error,
27-
fetchUsers,
28-
removeUser
29-
} = useUsers()
22+
// Initialize the composable state as null initially
23+
let usersComposable: ReturnType<typeof useUsers> | null = null
24+
25+
// Create computed properties that safely access the composable
26+
const users = computed(() => usersComposable?.users.value ?? [])
27+
const pagination = computed(() => usersComposable?.pagination.value ?? null)
28+
const loading = computed(() => usersComposable?.loading.value ?? false)
29+
const error = computed(() => usersComposable?.error.value ?? null)
3030
3131
onMounted(() => {
32+
// Initialize the composable only after the component is mounted
33+
usersComposable = useUsers()
34+
3235
// Fetch users only if the list is empty to avoid unnecessary fetches
3336
if (users.value.length === 0) {
34-
fetchUsers()
37+
usersComposable.fetchUsers()
3538
}
3639
})
3740
3841
const handleDelete = (user: User) => {
39-
removeUser(user.id)
42+
if (usersComposable) {
43+
usersComposable.removeUser(user.id)
44+
}
4045
emit('delete', user)
4146
}
47+
48+
const handleFetchUsers = (page?: number, limit?: number) => {
49+
if (usersComposable) {
50+
usersComposable.fetchUsers(page, limit)
51+
}
52+
}
4253
</script>
4354

4455
<template>
@@ -117,23 +128,23 @@ const handleDelete = (user: User) => {
117128
<slot
118129
name="pagination"
119130
:pagination="pagination"
120-
:fetch-users="fetchUsers"
131+
:fetch-users="handleFetchUsers"
121132
:loading="loading"
122133
>
123134
<div v-if="pagination && pagination.totalPages > 1">
124135
<div>
125136
<button
126137
v-if="pagination.hasPrev"
127138
:disabled="loading"
128-
@click="fetchUsers(pagination.page - 1)"
139+
@click="handleFetchUsers(pagination.page - 1)"
129140
>
130141
Previous
131142
</button>
132143

133144
<button
134145
v-if="pagination.hasNext"
135146
:disabled="loading"
136-
@click="fetchUsers(pagination.page + 1)"
147+
@click="handleFetchUsers(pagination.page + 1)"
137148
>
138149
Next
139150
</button>

src/runtime/components/NUsersLogoutLink.vue

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { ref } from 'vue'
2+
import { ref, onMounted } from 'vue'
33
import { navigateTo } from '#app'
44
import { useAuthentication } from '../composables/useAuthentication'
55
@@ -30,23 +30,34 @@ const props = withDefaults(defineProps<LogoutLinkProps>(), {
3030
3131
const emit = defineEmits<Emits>()
3232
33-
const { logout } = useAuthentication()
33+
// Initialize the composable state as null initially
34+
let authComposable: ReturnType<typeof useAuthentication> | null = null
3435
const isLoading = ref(false)
3536
const error = ref('')
3637
38+
onMounted(() => {
39+
// Initialize the composable only after the component is mounted
40+
authComposable = useAuthentication()
41+
})
42+
3743
const handleLogout = async (event: Event) => {
3844
event.preventDefault()
3945
4046
if (!confirm(props.confirmMessage)) {
4147
return
4248
}
4349
50+
if (!authComposable) {
51+
error.value = 'Authentication not initialized'
52+
return
53+
}
54+
4455
isLoading.value = true
4556
error.value = ''
4657
4758
try {
4859
emit('click')
49-
await logout()
60+
await authComposable.logout()
5061
emit('success')
5162
5263
// Redirect if specified

src/runtime/components/NUsersProfileInfo.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
<script setup lang="ts">
2+
import { computed, onMounted } from 'vue'
23
import { useAuthentication } from '../composables/useAuthentication'
34
4-
const { user } = useAuthentication()
5+
// Initialize the composable state as null initially
6+
let authComposable: ReturnType<typeof useAuthentication> | null = null
7+
8+
// Create computed property that safely accesses the composable
9+
const user = computed(() => authComposable?.user.value ?? null)
10+
11+
onMounted(() => {
12+
// Initialize the composable only after the component is mounted
13+
authComposable = useAuthentication()
14+
})
515
</script>
616

717
<template>

src/runtime/components/NUsersUserCard.vue

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { computed } from 'vue'
2+
import { computed, onMounted } from 'vue'
33
import { useAuthentication } from '../composables/useAuthentication'
44
import { useRuntimeConfig } from '#imports'
55
import { defaultDisplayFields, defaultFieldLabels, type User } from 'nuxt-users/utils'
@@ -22,9 +22,19 @@ const emit = defineEmits<{
2222
(e: 'delete' | 'editClick', user: User): void
2323
}>()
2424
25-
const { user: currentUser } = useAuthentication()
2625
const { public: { nuxtUsers } } = useRuntimeConfig()
2726
27+
// Initialize the custom composable state as null initially
28+
let authComposable: ReturnType<typeof useAuthentication> | null = null
29+
30+
// Create computed property that safely accesses the composable
31+
const currentUser = computed(() => authComposable?.user.value ?? null)
32+
33+
onMounted(() => {
34+
// Initialize the custom composable only after the component is mounted
35+
authComposable = useAuthentication()
36+
})
37+
2838
const canEdit = computed(() => {
2939
if (!currentUser.value) return false
3040

0 commit comments

Comments
 (0)