javascript - Next.js: `onSubmit` 未执行回调函数
在我的 Next.js 模块中,我声明了一个表单,如下所示:
<form onSubmit = {() => {
async() => await getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
console.log("getCertificate completed")
}}>
函数 getCertificate() 定义在与以下内容相同的 .tsx 文件中:
async function getCertificate(id: string) : Promise<Response> {
console.log("in getCertificate")
const resp = await fetch(`${serverUri}/certs/${id}`)
console.log(`Response data: ${await resp.json()}`)
return resp
}
看起来 getCertificate() 根本没有被调用。虽然我在 onSubmit 处理函数中的最终 console.log("getCertificate completed") 正确执行,但 getCertificate() 内的任何 console.log() 语句都没有被执行。
没有错误被抛出或记录到控制台。控制台中出现的唯一内容(除了getCertificate completed)是Navigated to http://localhost:3000/?certId=my_cert_id。
有什么想法为什么它会这样表现吗?
(唯一需要注意的其他事项是,我的 .tsx 文件使用了 'use client' 装饰,因为我在某些其他功能中使用了客户端库,并且我的表单定义位于 export default function 的 return 语句内。除此之外,所有功能都按预期工作,唯一的问题是 getCertificates() 没有被触发。)
答案#1
可能的解决方案
如果唯一的问题是执行 getCertificate,那么你可以尝试做如下操作:
import React, { useState } from "react";
const serverUri = "http://myserver.com";
export default function Certificate() {
const [id, setId] = useState("");
async function getCertificate(id: string): Promise<Response> {
console.log("in getCertificate");
const resp = await fetch(`${serverUri}/certs/${id}`);
console.log(`Response data: ${await resp.json()}`);
return resp;
}
return (
<form onSubmit={async (event: any) => {
event.preventDefault();
try {
const response = await getCertificate(id);
const data = await response.json();
console.log(data);
} catch (err) {
console.error(err);
}
console.log("getCertificate completed");
}}>
<label>
Certificate ID:
<input type="text" value={id} onChange={e => setId(e.target.value)} />
</label>
<button type="submit">Submit</button>
</form>
);
}
如你在截图中所见,in getCertificate 已打印到控制台。
无法执行的原因
让我们仔细看看原始函数:
() => {
async() => await getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
console.log("getCertificate completed")
}
如您在这里看到的,您只需在此处定义一个匿名异步箭头函数(不将该函数赋值给任何变量,因此该函数从未被调用),然后只执行 console.log。所以 console.log 是唯一实际被执行的内容。
另外,你在调用 getCertificate 前添加了 await,这是不必要的,可能会导致额外的混淆。
让我们简化这行代码
async() => await getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
所以首先我们将重新格式化代码以查看其结构:
async() => {
await getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
}
然后我们删除不必要的函数定义:
await getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
然后我们将移除不必要的 await:
getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.catch(err => console.error(err))
另一个解决方案
因此,使用前一节中的变换,我们可以得到定义整个函数的另一种方法。
(event: any) => {
event.preventDefault();
getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.then(() => console.log("getCertificate completed with no errors"))
.catch(err => console.error(err))
.then(() => console.log("getCertificate completed with errors"))
}
附言
请注意,两个解决方案中的 event.preventDefault() 都会阻止表单数据的实际传输,并将强制在 JS 中处理所有内容。它是可选的,可以省略。
答案#2
你将 getCertificate 调用包装在一个匿名函数中,而你实际上从未调用过它。从表面上看,根本不需要那个包装函数,所以你可以将其内部逻辑直接提升到 onSubmit 函数中,像这样:
<form onSubmit = {async () => {
try {
const resp = await getCertificate(id);
const data = await resp.json();
console.log(data);
console.log("getCertificate completed");
} catch (err) {
console.error(err)
}
}}>
或者使用 promise 链式调用:
<form onSubmit = {() => {
getCertificate(id)
.then(async resp => await resp.json())
.then(data => console.log(data))
.then(() => console.log("getCertificate completed"))
.catch(err => console.error(err))
}}>
我建议你坚持使用 async/await 或者 promise 链,而不是混合使用,因为混合使用会让逻辑更难理解。就我个人而言,我推荐 async/await。
