Mähh
Mähh
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
PS: Code is not tested, maybe it need adjustements 🙂
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
So a better example would be:
const fetchMessage = async () => {
const myAsyncDataObj = { pending: ref(true), data: ref(null) }

const promise = new Promise((resolve) => {
setTimeout(() => {
myAsyncDataObj.pending.value.value = false
myAsyncDataObj.pending.data.value = 'Hello world'

return myAsyncData
}, 1000);
});

return Object.assign(promise, myAsyncDataObj)
}
const fetchMessage = async () => {
const myAsyncDataObj = { pending: ref(true), data: ref(null) }

const promise = new Promise((resolve) => {
setTimeout(() => {
myAsyncDataObj.pending.value.value = false
myAsyncDataObj.pending.data.value = 'Hello world'

return myAsyncData
}, 1000);
});

return Object.assign(promise, myAsyncDataObj)
}
Which could be accessed by a similar logic
const {data: message, pending} = await fetchMessage()
const {data: message, pending} = await fetchMessage()
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
but there the data and pending is a reference / reactive prop itself.
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
its similar like in the useAsyncData https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts#L395-L398
const asyncDataPromise = Promise.resolve(nuxtApp._asyncDataPromises[key]).then(() => asyncData) as AsyncData<ResT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>)>

Object.assign(asyncDataPromise, asyncData)

return asyncDataPromise
const asyncDataPromise = Promise.resolve(nuxtApp._asyncDataPromises[key]).then(() => asyncData) as AsyncData<ResT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>)>

Object.assign(asyncDataPromise, asyncData)

return asyncDataPromise
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
you could do it like nuxt:
const message = ref({ pending: false, data: null })

const fetchMessage = async () => {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve({ pending: false, data: 'My message' });
}, 1000);
});

return Object.assign(promise, { pending: true, data: null })
};

message.value = await fetchMessage()
const message = ref({ pending: false, data: null })

const fetchMessage = async () => {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve({ pending: false, data: 'My message' });
}, 1000);
});

return Object.assign(promise, { pending: true, data: null })
};

message.value = await fetchMessage()
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
Do i get it correctly, you wan't some logic like the default from useAsyncData where you don't only have the Promise, instead also can access the fields like data, error, status and so on without the Promise is done?
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
Checked the source code: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts#L251C5-L257C6
nuxtApp._asyncData[key] = {
data: _ref(typeof cachedData !== 'undefined' ? cachedData : options.default!()),
pending: ref(!hasCachedData()),
error: toRef(nuxtApp.payload._errors, key),
status: ref('idle'),
_default: options.default!,
}
nuxtApp._asyncData[key] = {
data: _ref(typeof cachedData !== 'undefined' ? cachedData : options.default!()),
pending: ref(!hasCachedData()),
error: toRef(nuxtApp.payload._errors, key),
status: ref('idle'),
_default: options.default!,
}
This is what happens behind useFetch and useAsyncData you could use that to get all the status references and return a bool to know if any useFetch or useAsyncData is pending / refreshing. For the custom $fetch here is an example for the plugin way: https://nuxt.com/docs/guide/recipes/custom-usefetch
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
plugin would be more elegant way to inject $myFetch globally. Anyways, i think you got the point. Have a state which is aware of pending requests in you application, by intercept the requests by its core methods 😄
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
for $fetch the same could be used. e.g. implement a global $myFetch via plugin, or just using a composable like:
export const $myFetch = () => {
const {pendingCount} = useRequestState()

return $fetch.create({
onRequest() {
++pendingCount.value
},
onResponseError() {
--pendingCount.value
},
onResponse() {
--pendingCount.value
}
})
}
export const $myFetch = () => {
const {pendingCount} = useRequestState()

return $fetch.create({
onRequest() {
++pendingCount.value
},
onResponseError() {
--pendingCount.value
},
onResponse() {
--pendingCount.value
}
})
}
Which can be called in components
$myFetch()('/foo', { method: 'POST' })
$myFetch()('/foo', { method: 'POST' })
30 replies
NNuxt
Created by AxelSorensen on 7/18/2024 in #❓・help
Automatic pending state for data being fetched?
what about a custom $fetch wrapper? (btw. your are right: useFetch only should be used for getting data, not for update or create requests, for that $fetch should be used, thats because of internal caching logic behind useAsyncData / useFetch i guess) Anyways.
export const useRequestState () => {
const pendingCount = useState('requests-pending', () => 0)
const pending = computed(() => pendingRequests.value > 0)

return { pendingCount, pending }
}
export const useRequestState () => {
const pendingCount = useState('requests-pending', () => 0)
const pending = computed(() => pendingRequests.value > 0)

return { pendingCount, pending }
}
export const useMyCustomFetch = (request, opts) => {
const {pendingCount} = useRequestState()

return useFetch(request, {
...opts,
onRequest() {
++pendingCount.value
},
onResponseError() {
--pendingCount.value
},
onResponse() {
--pendingCount.value
}
})
}
export const useMyCustomFetch = (request, opts) => {
const {pendingCount} = useRequestState()

return useFetch(request, {
...opts,
onRequest() {
++pendingCount.value
},
onResponseError() {
--pendingCount.value
},
onResponse() {
--pendingCount.value
}
})
}
30 replies
NNuxt
Created by lav on 7/15/2024 in #❓・help
UseState with a state coming from a db
10 replies
NNuxt
Created by lav on 7/15/2024 in #❓・help
UseState with a state coming from a db
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.
10 replies
NNuxt
Created by lav on 7/15/2024 in #❓・help
UseState with a state coming from a db
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.
10 replies
NNuxt
Created by lav on 7/15/2024 in #❓・help
UseState with a state coming from a db
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>
10 replies
NNuxt
Created by lav on 7/15/2024 in #❓・help
UseState with a state coming from a db
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
}
})
10 replies
NNuxt
Created by Mähh on 6/26/2024 in #❓・help
useCookie does share state between layout and component when used in composable
Not tested yet, but saw the comment:
This is related to the now switched-on cookieStore feature. As a workaround, disabling it for now (experimental.cookieStore to false) should resolve the issue.
This is related to the now switched-on cookieStore feature. As a workaround, disabling it for now (experimental.cookieStore to false) should resolve the issue.
Maybe this also works for 3.12 instead downgrading
6 replies
NNuxt
Created by lav on 7/12/2024 in #❓・help
State not changing when using a composables
<script setup lang="ts">
interface MyProps {
playerId: number
}

const props = defineProps<MyProps>()

const {itsReactive} = useTest(props)
</script>

<template>
<div>
player id props: {{ props.playerId }}<br/>
composable player id: {{itsReactive}}
</div>
</template>
<script setup lang="ts">
interface MyProps {
playerId: number
}

const props = defineProps<MyProps>()

const {itsReactive} = useTest(props)
</script>

<template>
<div>
player id props: {{ props.playerId }}<br/>
composable player id: {{itsReactive}}
</div>
</template>
export default (props) => {
const itsReactive = computed(() => props.playerId)

watch(() => props.playerId, (newVal, oldVal) => {
console.log('changed', newVal, oldVal)
})

return {
itsReactive
}
}
export default (props) => {
const itsReactive = computed(() => props.playerId)

watch(() => props.playerId, (newVal, oldVal) => {
console.log('changed', newVal, oldVal)
})

return {
itsReactive
}
}
Works for me.
13 replies
NNuxt
Created by lav on 7/12/2024 in #❓・help
State not changing when using a composables
So:
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
computed(() => props.playerId)
)
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
computed(() => props.playerId)
)
Would work, while
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
)
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
)
will not.
13 replies
NNuxt
Created by lav on 7/12/2024 in #❓・help
State not changing when using a composables
Wait, even if props are reactive, not every value in props is reactive. So if you pass props.playerId to a composable, the value of it within the composable is not reactive anymore. If props.playerId change within the component, the composable still keeps the old value, so the watcher in your composable:
export default (playerId) => {
watch(() => playerId, {
console.log('playerId changed')
})
}
export default (playerId) => {
watch(() => playerId, {
console.log('playerId changed')
})
}
will not trigger, since only the props is reactive, not the props.playerId itself. So if you pass const foo = myComposable(props.playerId) you do not get the changes. You need to pass actually a ref / computed or the whole props object to keep the reactivity across your component and composable.
13 replies
NNuxt
Created by ægteemil on 7/12/2024 in #❓・help
Route guards for user permissions
as long as you do not work with nested pages: yes.
5 replies