Since Nuxt's fetch hooks cannot run in parallel I needed a way to cancel request done in fetch hook when navigating to some other route so users don't have to wait for the first fetch to complete when landed on homepage and then navigated to some other. So I found this approach: How to cancel all axios requests on route change
So I've created these plugin files for Nuxt:
router.js
export default ({ app, store }) => {
// Every time the route changes (fired on initialization too)
app.router.beforeEach((to, from, next) => {
store.dispatch('cancel/cancel_pending_requests')
next()
})
}
axios.js
export default function ({ $axios, redirect, store }) {
$axios.onRequest((config) => {
const source = $axios.CancelToken.source()
config.cancelToken = source.token
store.commit('cancel/ADD_CANCEL_TOKEN', source)
return config
}, function (error) {
return Promise.reject(error)
})
}
and a small vuex store for the cancel tokens:
export const state = () => ({
cancelTokens: []
})
export const mutations = {
ADD_CANCEL_TOKEN (state, token) {
state.cancelTokens.push(token)
},
CLEAR_CANCEL_TOKENS (state) {
state.cancelTokens = []
}
}
export const actions = {
cancel_pending_requests ({ state, commit }) {
state.cancelTokens.forEach((request, i) => {
if (request.cancel) {
request.cancel('Request canceled')
}
})
commit('CLEAR_CANCEL_TOKENS')
}
}
Now this approach works fine and I can see requests get canceled with 499 on route change, however it is flooding my devtools console with "Error in fetch()" error. Is there some preffered/better way to do this ?
Example of fetch hook here:
async fetch () {
await this.$store.dispatch('runs/getRunsOverview')
}
Example of dispatched action:
export const actions = {
async getRunsOverview ({ commit }) {
const data = await this.$axios.$get('api/frontend/runs')
commit('SET_RUNS', data)
}
}
Edit: Forgot to mention that I'm using fetch here with fetchOnServer set to False so i can display some loading placeholder to users.
The main problem is the flooded console with error but i can also see that it enters also the $fetchState.error branch in my template which just displays div with "Something went wrong" text before route switches.
Edit 2: Looked closer where this error comes from and it's mixin file fetch.client.js in .nuxt/mixins directory. Pasting the fetch function code below:
async function $_fetch() {
this.$nuxt.nbFetching++
this.$fetchState.pending = true
this.$fetchState.error = null
this._hydrated = false
let error = null
const startTime = Date.now()
try {
await this.$options.fetch.call(this)
} catch (err) {
if (process.dev) {
console.error('Error in fetch():', err)
}
error = normalizeError(err)
}
const delayLeft = this._fetchDelay - (Date.now() - startTime)
if (delayLeft > 0) {
await new Promise(resolve => setTimeout(resolve, delayLeft))
}
this.$fetchState.error = error
this.$fetchState.pending = false
this.$fetchState.timestamp = Date.now()
this.$nextTick(() => this.$nuxt.nbFetching--)
}
Have also tried to have everything using async/await as @kissu suggested in comments but with no luck :/
from Canceling request of nuxt fetch hook
No comments:
Post a Comment