NextJS中Fetch API需按两次回车键才生效问题排查
问题:搜索框回车后需两次触发才能获取正确结果
组件预期功能:在搜索框输入内容后按下回车键,控制台打印对应JSON数据。但实际存在以下问题:
- 首次输入内容按回车,控制台无输出,需再按一次才打印结果
- 修改搜索内容后按回车,返回的是上一次搜索的结果,再次按回车才能获取当前搜索结果
可输入Reinforcements或Contact进行测试,原代码如下:
import { Box, Input } from "@chakra-ui/react"; import styles from "../styles/search.module.css"; import React, { useState } from "react"; export default function Search() { const [cardName, setCardName] = useState(""); const [searchCard, setSearchCard] = useState(""); const handleChange = (event) => { setCardName(event.target.value); }; const handleKeyDown = (event) => { if (event.key == "Enter") { setSearchCard(cardName); fetch(`https://db.ygoprodeck.com/api/v7/cardinfo.php?name=${searchCard}`) .then((response) => response.json()) .then((json) => console.log(json)); } }; return ( <> <Box className={styles.container}> <Input size="lg" bg="#e8f1f2" placeholder="Search for a card" id="cardName" name="cardName" value={cardName} onChange={handleChange} onKeyDown={handleKeyDown} className={styles.input} ></Input> <ul className={styles.list}></ul> </Box> </> ); }
问题原因
React的setState是异步更新状态的。在handleKeyDown函数里,调用setSearchCard(cardName)后立刻使用searchCard发起请求,此时searchCard还没完成更新,依然是旧值,导致请求用的是上一次的搜索关键词,所以需要第二次回车才能拿到正确结果。
解决方案
方案一:直接使用当前输入值发起请求(简洁版)
不需要额外维护searchCard状态,直接用cardName的值发起请求,避免异步状态更新的问题:
import { Box, Input } from "@chakra-ui/react"; import styles from "../styles/search.module.css"; import React, { useState } from "react"; export default function Search() { const [cardName, setCardName] = useState(""); const handleChange = (event) => { setCardName(event.target.value); }; const handleKeyDown = (event) => { if (event.key === "Enter") { // 直接使用当前输入的cardName发起请求 fetch(`https://db.ygoprodeck.com/api/v7/cardinfo.php?name=${cardName}`) .then((response) => response.json()) .then((json) => console.log(json)); } }; return ( <> <Box className={styles.container}> <Input size="lg" bg="#e8f1f2" placeholder="Search for a card" id="cardName" name="cardName" value={cardName} onChange={handleChange} onKeyDown={handleKeyDown} className={styles.input} ></Input> <ul className={styles.list}></ul> </Box> </> ); }
方案二:用useEffect监听状态变化(适合需保留搜索词的场景)
如果需要把搜索关键词存下来做其他用途(比如显示当前搜索词、记录历史),可以用useEffect监听searchCard的变化,等状态更新完成后再发起请求:
import { Box, Input } from "@chakra-ui/react"; import styles from "../styles/search.module.css"; import React, { useState, useEffect } from "react"; export default function Search() { const [cardName, setCardName] = useState(""); const [searchCard, setSearchCard] = useState(""); const handleChange = (event) => { setCardName(event.target.value); }; const handleKeyDown = (event) => { if (event.key === "Enter") { setSearchCard(cardName); } }; // 当searchCard状态更新时,发起请求 useEffect(() => { if (searchCard) { fetch(`https://db.ygoprodeck.com/api/v7/cardinfo.php?name=${searchCard}`) .then((response) => response.json()) .then((json) => console.log(json)); } }, [searchCard]); return ( <> <Box className={styles.container}> <Input size="lg" bg="#e8f1f2" placeholder="Search for a card" id="cardName" name="cardName" value={cardName} onChange={handleChange} onKeyDown={handleKeyDown} className={styles.input} ></Input> <ul className={styles.list}></ul> </Box> </> ); }
内容的提问来源于stack exchange,提问作者MasterYoshi97
相关产品推荐
相关产品推荐

