N
Nuxt2mo ago
sirlav0ie

UseState with a state coming from a db

Hello, I've issue with reactive state for useState, I fetch players from a DB and place them into the global state, but the components getting the global state are not updating to get the version that is coming from client side rendering when i load the page from another page.
export function useRetrievePlayers() {
const { data } = useFetch('/api/baseball/retrieve-players');

const players = computed(() => {
console.log('data', data.value);
if (!data.value) {
return [];
}

return data.value.players;
});

return players;
}
export function useRetrievePlayers() {
const { data } = useFetch('/api/baseball/retrieve-players');

const players = computed(() => {
console.log('data', data.value);
if (!data.value) {
return [];
}

return data.value.players;
});

return players;
}
This is my composables that I use in parent:
const players = useRetrievePlayers();
useState('players', () => players);
const players = useRetrievePlayers();
useState('players', () => players);
I've tried using my useState in my computed prop it didnt work either. I retrieve it like so in child:
const { value: players } = useState('players');
const { value: players } = useState('players');
I am pretty new to vue/nuxt sorry. I do not know if this is a good way to use the global store either Each component are children of each other so I could've done prop drilling or injection. I think it would be a better fit ig, but I wanna know if what I want to do is possible
7 Replies
sirlav0ie
sirlav0ie2mo ago
I was also using global state bcs I had to pass into a to a lot of different children but each one used it so... Maybe I am using global state wrong. This is also a quesiton when you would use global state.
Timo
Timo2mo ago
if you simply want to display the players of the db try
export const useRetrievePlayers = () => useFetch('/api/baseball/retrieve-players', {
default: () => []
});
export const useRetrievePlayers = () => useFetch('/api/baseball/retrieve-players', {
default: () => []
});
and in your component
const { data: players } = useRetrievePlayers();

// use reactive players
const { data: players } = useRetrievePlayers();

// use reactive players
this approach does not use global state but it seems like it suits your needs. useFetch deduplicates the requests automatically, so on page load all components will trigger only one request. more here
Nuxt
useFetch · Nuxt Composables
Fetch data from an API endpoint with an SSR-friendly composable.
Mähh
Mähh2mo ago
useFetch does not prevent multiple fetches, if you use that composable in e.g. 4 components it will fetch 4 times. You can prevent that by define the cachedata:
useFetch('/api&goo', {
getCachedData(key, nuxtApp) {
return useNuxtData(key).data.value
}
})
useFetch('/api&goo', {
getCachedData(key, nuxtApp) {
return useNuxtData(key).data.value
}
})
This will make sure your fetch does not trigger multiple times. But you need to call the refresh() method, in case you want to load the data again. From docs:
getCachedData: Provide a function which returns cached data. A null or undefined return value will trigger a fetch. By default, this is: key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key], which only caches data when payloadExtraction is enabled.
getCachedData: Provide a function which returns cached data. A null or undefined return value will trigger a fetch. By default, this is: key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key], which only caches data when payloadExtraction is enabled.
useFetch is the same as
useAsyncData('my-custom-key', async () => $fetch('/api/foo'))
useAsyncData('my-custom-key', async () => $fetch('/api/foo'))
Just with "auto key generation" based on URL and options passed for the request. --- If you rely on multiple global states, i would recommend pinia for store / state management: https://nuxt.com/modules/pinia Stores are in the nuxt context ,so they are builded very similar to composables itself. stores/my-store.ts
export const useMyStore = defineStore('my-store', () => {
const isInitialized = ref(false)
const players = ref([])

const fetchPlayers = async () => {
players.value = await $fetch('/api/players')
}

return {players, isInitialized, fetchPlayers}
})
export const useMyStore = defineStore('my-store', () => {
const isInitialized = ref(false)
const players = ref([])

const fetchPlayers = async () => {
players.value = await $fetch('/api/players')
}

return {players, isInitialized, fetchPlayers}
})
But you cannot initialize the state itself in the store. Since the hydration of the state between SSR und CSR are after the execution / initialization of the store itself. I handle that with middlewares whenever i have global states which are e.g. delivered by an api: middlewares/context.global.ts
export default defineNuxtRouteMiddleware(async () => {
const {isInitialized} = storeToRefs(useMyStore())
const {fetchPlayers} = useMyStore()

if (!isInitialized.value) {
await fetchPlayers()
isInitialized.value = true
}
})
export default defineNuxtRouteMiddleware(async () => {
const {isInitialized} = storeToRefs(useMyStore())
const {fetchPlayers} = useMyStore()

if (!isInitialized.value) {
await fetchPlayers()
isInitialized.value = true
}
})
In components you can access the state with:
<script setup lang="ts">
const {players} = storeToRefs(useMyStore())
</script>

<template>
<div>
{{players}}
</div>
</template>
<script setup lang="ts">
const {players} = storeToRefs(useMyStore())
</script>

<template>
<div>
{{players}}
</div>
</template>
Timo
Timo2mo ago
at least in the docs it says
key: a unique key to ensure that data fetching can be properly de-duplicated across requests, if not provided, it will be automatically generated based on URL and fetch options
Mähh
Mähh2mo ago
Yep, but:
If you provide a function or ref as the url parameter, or if you provide functions as arguments to the options parameter, then the useFetch call will not match other useFetch calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in options.
If you provide a function or ref as the url parameter, or if you provide functions as arguments to the options parameter, then the useFetch call will not match other useFetch calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in options.
https://stackblitz.com/edit/nuxt-starter-zckkxt I'm with you, it should be prevent the fetching, at least for simple cases like:
useFetch('/api/foo')
useFetch('/api/foo')
But only setting a key option, will prevent duplicated requests, when used in multiple components.
Mähh
Mähh2mo ago
GitHub
useFetch only prevents multiple requests when key option is set ·...
Environment Operating System: Darwin Node Version: v20.11.0 Nuxt Version: 3.12.3 CLI Version: 3.12.0 Nitro Version: 2.9.7 Package Manager: bun@1.1.18 Builder: - User Config: compatibilityDate, devt...
sirlav0ie
sirlav0ie2mo ago
Thanks
Want results from more Discord servers?
Add your server