英文:
HTTP request outside setInterval is executed for every setInterval iteration when using @pinia/nuxt
问题
我正在尝试使用 @pinia/nuxt 和 nuxt 3 构建一个定时器。我还希望在启动定时器时进行 HTTP 请求,以同步我的数据库。
我面临的问题是,每次调用 start
动作时,都会在 setInterval
的每次迭代中进行 HTTP 请求,而我只想运行一次。
这是 Pinia 模块。我从组件的 onClick
事件中调用 start
动作。
state: () => ({
timer: {
id: null,
isRunning: false,
time: 5,
timer: 0,
state: null,
} as Timer,
}),
actions: {
start() {
this.timer.isRunning = true
this.syncTimer()
if (!this.timer.timer) {
this.timer.timer = setInterval(() => {
if (this.timer.time > 0) {
this.timer.time--
} else {
clearInterval(this.timer.timer)
this.reset()
}
}, 1000)
}
},
stop() {
this.timer.isRunning = false
clearInterval(this.timer.timer)
this.timer.timer = 0
},
reset() {
this.stop()
this.timer.time = 1500
},
syncTimer() {
backendAPI('/api/timer', {
method: 'POST',
body: this.timer
}).then(({ error, data }) => {
if (!error.value) {
const id = data.value?.id ?? ""
this.timer.id = id
this.timer.state = "created"
}
})
}
}
自定义 fetch 可组合性 backendAPI.ts
:
import type { UseFetchOptions } from 'nuxt/app'
import { useUserStore } from '@/stores/user'
import { defu } from 'defu'
export function backendAPI<T>(url: string, options: UseFetchOptions<T> = {}) {
const config = useRuntimeConfig()
const { token } = useUserStore();
const appToken = useRuntimeConfig().public.appToken
const defaults: UseFetchOptions<T> = {
baseURL: config.public.baseURL ?? 'http://localhost:4000',
key: url,
params: {
token: appToken
},
headers: token
? { Authorization: `Bearer ${token}` }
: {},
}
const params = defu(options, defaults)
return useFetch(url, params)
}
英文:
I am trying to build a timer using @pinia/nuxt with nuxt 3. I also want to make an http request when the timer is started to sync my db.
The problem I am facing is that whenever I call the action start
, the http request is made for each iteration of setInterval
and I only want to run it once.
This is the pinia module. I am calling the start
action from an onClick
event in a component.
state: () => ({
timer: {
id: null,
isRunning: false,
time: 5,
timer: 0,
state: null,
} as Timer,
}),
actions: {
start() {
this.timer.isRunning = true
this.syncTimer()
if (!this.timer.timer) {
this.timer.timer = setInterval(() => {
if (this.timer.time > 0) {
this.timer.time--
} else {
clearInterval(this.timer.timer)
this.reset()
}
}, 1000)
}
},
stop() {
this.timer.isRunning = false
clearInterval(this.timer.timer)
this.timer.timer = 0
},
reset() {
this.stop()
this.timer.time = 1500
},
syncTimer() {
backendAPI<Timer>('/api/timer', {
method: 'POST',
body: this.timer
}).then(({ error, data }) => {
if (!error.value) {
const id = data.value?.id ?? ""
this.timer.id = id
this.timer.state = "created"
}
})
}
}
Custom fetch composable backendAPI.ts
:
import type { UseFetchOptions } from 'nuxt/app'
import { useUserStore } from '@/stores/user'
import { defu } from 'defu'
export function backendAPI<T>(url: string, options: UseFetchOptions<T> = {}) {
const config = useRuntimeConfig()
const { token } = useUserStore();
const appToken = useRuntimeConfig().public.appToken
const defaults: UseFetchOptions<T> = {
baseURL: config.public.baseURL ?? 'http://localhost:4000',
key: url,
params: {
token: appToken
},
headers: token
? { Authorization: `Bearer ${token}` }
: {},
}
const params = defu(options, defaults)
return useFetch(url, params)
}
答案1
得分: 0
正如我在评论中提到的,实现实时特性的正确方法是使用套接字(sockets)。但是,如果你需要以轮询方式进行,可以编写一个保护程序,类似于这样:
actions: {
start() {
if (this.timer.isRunning) return;
this.timer.isRunning = true;
this.syncTimer();
this.timer.timer = setInterval(() => {
if (this.timer.time > 0) {
this.timer.time--;
} else {
clearInterval(this.timer.timer);
this.reset();
}
}, 1000);
},
// ...
}
希望这对你有所帮助。
英文:
As I mentioned in the comments, the correct way of implementing realtime feature, is to use sockets. But, if you need to do it in a polling style, you can write a guard, something like this:
actions: {
start() {
if (this.timer.isRunning) return;
this.timer.isRunning = true;
this.syncTimer();
this.timer.timer = setInterval(() => {
if (this.timer.time > 0) {
this.timer.time--;
} else {
clearInterval(this.timer.timer);
this.reset();
}
}, 1000);
},
// ...
}
Hope this helps.
答案2
得分: 0
以下是您要翻译的内容:
问题似乎与 Nuxt 3 的 useFetch
函数相关。
来自 Nuxt 文档:
> 所有的 fetch 选项都可以使用 computed 或 ref 值。如果这些值被更新,它们将被监视,并自动使用新值进行新的请求。
因此,每当计时器值更新时,useFecth
将自动发出新请求。
将 watch: false
添加到请求中解决了我的问题。
backendAPI<Timer>('/api/timer', {
method: 'POST',
watch: false,
body: this.timer
}).then(({ error, data }) => {
if (!error.value) {
const id = data.value?.id ?? ""
this.timer.id = id
this.timer.state = "created"
}
})
英文:
The problem seems to be related to the nuxt 3 useFetch
function.
From the nuxt documentation:
> All fetch options can be given a computed or ref value. These will be watched and new requests made automatically with any new values if they are updated.
So every time the timer value is updated, useFecth
will automatically make a new request.
Adding watch: false
to the request solved my problem
backendAPI<Timer>('/api/timer', {
method: 'POST',
watch: false,
body: this.timer
}).then(({ error, data }) => {
if (!error.value) {
const id = data.value?.id ?? ""
this.timer.id = id
this.timer.state = "created"
}
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论