
标签:Nuxt3、useFetch、表单提交、API 请求
最近在写一个 Nuxt 项目的时候,我遇到了一个特别奇怪的问题:表单中有个 email 输入框,本来只需要在点击“保存”按钮后调用接口 /api/saveUserInfo,但发现每次修改 email 的值时,接口都会自动请求!最诡异的是,明明我的代码里没有调用 save 方法啊…

来看下面这段代码:
const form = ref({ email: '' });
const { data, error } = useFetch('api/hello', {
method: 'POST',
body: { email: form.value.email }
});
const save = () => {
console.log('点击保存按钮时调用接口');
};本意是点击按钮时手动触发 save 方法,但每次 email 的值改变时,接口竟然自己就跑了。查了很久才发现,这一切的罪魁祸首是 useFetch 的 自动监听机制。
Nuxt 的 useFetch 方法有一个默认行为:当传入的参数(如 body)的值发生变化时,会自动重新发起请求。换句话说,form.value.email 是个引用类型,它的变化触发了 useFetch 的重新调用。
官方文档也提到:Nuxt useFetch - watch:
默认情况下,
useFetch会监听参数值的变化,并重新触发请求。
针对这个问题,有以下几种解决办法:
body 参数直接传对象的引用会导致监听触发,所以可以传入 字段值 而非对象:
const { data, error } = useFetch('api/hello', {
method: 'POST',
body: { email: form.value.email } // 保持单字段传递
});这样,只有手动调用 useFetch 或点击按钮时,接口才会发起请求。
如果你需要传入整个 form 对象,但又不想触发监听,可以在 useFetch 中关闭 watch:
const { data, error } = useFetch('api/hello', {
method: 'POST',
body: form.value,
watch: false // 关闭监听
});watch: false 明确告诉 useFetch,不要监听参数变化。
如果你非要传复杂对象,也可以通过 JSON.stringify 将其转为字符串,这样 Nuxt 无法自动检测变化:
const { data, error } = useFetch('api/hello', {
method: 'POST',
body: JSON.stringify(form.value)
});字符串化后,即使对象内容发生变化,也不会触发重新请求。
根据场景选择合适的方案:
以下是修改后的完整代码:
<script setup>
import { ref } from 'vue';
const form = ref({ email: '' });
const save = async () => {
console.log('点击保存按钮时调用接口');
const { data, error } = await useFetch('api/hello', {
method: 'POST',
body: { email: form.value.email }, // 推荐方式:传单字段
watch: false, // 可选:关闭自动监听
});
if (error.value) {
console.error('请求失败:', error.value);
} else {
console.log('请求成功:', data.value);
}
};
</script>
<template>
<div>
<input v-model="form.email" placeholder="输入邮箱地址" />
<button @click="save">保存</button>
</div>
</template>通过上述方法,你可以避免 input 的值改变触发 useFetch 的自动请求问题。核心思想是:要么控制传递参数的类型,要么直接关闭监听。
遇到这种问题,一定要记住 Nuxt 的 useFetch 默认会“听”参数的变化,稍不注意就会“偷跑”请求。不过,了解了原理后解决起来也不难!