HTTP request outside setInterval is executed for every setInterval iteration when using @pinia/nuxt

huangapple go评论81阅读模式
英文:

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: () =&gt; ({
  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(() =&gt; {
        if (this.timer.time &gt; 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&lt;Timer&gt;(&#39;/api/timer&#39;, {
      method: &#39;POST&#39;,
      body: this.timer
    }).then(({ error, data }) =&gt; {
      if (!error.value) {
        const id = data.value?.id ?? &quot;&quot;
        this.timer.id = id
        this.timer.state = &quot;created&quot;
      }
    })
  }
}

Custom fetch composable backendAPI.ts:

import type { UseFetchOptions } from &#39;nuxt/app&#39;
import { useUserStore } from &#39;@/stores/user&#39;
import { defu } from &#39;defu&#39;

export function backendAPI&lt;T&gt;(url: string, options: UseFetchOptions&lt;T&gt; = {}) {
  const config = useRuntimeConfig()
  const { token } = useUserStore();
  const appToken = useRuntimeConfig().public.appToken

  const defaults: UseFetchOptions&lt;T&gt; = {
    baseURL: config.public.baseURL ?? &#39;http://localhost:4000&#39;,
    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(() =&gt; {
      if (this.timer.time &gt; 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&lt;Timer&gt;('/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&lt;Timer&gt;(&#39;/api/timer&#39;, {
  method: &#39;POST&#39;,
  watch: false,
  body: this.timer
}).then(({ error, data }) =&gt; {
  if (!error.value) {
    const id = data.value?.id ?? &quot;&quot;
    this.timer.id = id
    this.timer.state = &quot;created&quot;
  }
})

huangapple
  • 本文由 发表于 2023年7月18日 16:28:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76710848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定