React状态需点击两次按钮才更新,接口请求延迟问题排查
React组件首次搜索请求失败,二次点击才成功的解决方法
问题描述
从Express API获取数据时,后端接口运行正常,但前端存在以下问题:修改input内容后调用数据获取函数,状态更新有延迟,首次点击搜索按钮时请求失败,第二次点击才成功。
组件代码
import React, { useState, useEffect } from 'react'; import UsersList from './UsersList.js'; function SearchBox() { const [input, setInput] = useState(""); const [githubUserResult, setGithubUserResult] = useState([]); const [gitlabUserResult, setGitlabUserResult] = useState([]); const [isLoaded, setIsloaded] = useState(false); const [error, setError] = useState(null); const handleInputChange = (e) => { setInput(e.target.value); } const searchUser = async (e) => { e.preventDefault(); searchUserOnGithub(input); searchUserOnGitLab(input); setIsloaded(true); } const searchUserOnGithub = async (username) => { await fetch(`/api/github/userinfo/${username}`, { method: "GET", headers: { "Content-Type": "application/json", } }) .then(res => res.json()) .then( (result) => { setGithubUserResult(result); console.log(githubUserResult); }, (error) => { setError(error) }) } const searchUserOnGitLab = async (username) => { await fetch(`/api/gitlab/userinfo/${username}`, { method: "GET", headers: { "Content-Type": "application/json", } }) .then(res => res.json()) .then( (result) => { setGitlabUserResult(result); console.log(gitlabUserResult); }, (error) => { setError(error) }) } if (error) { return <div>Error: {error.message}</div>; }return ( <div className='search-container'> <form> <input type="text" onChange={handleInputChange} /> <button type="button" onClick={searchUser} >Search</button> </form> <h3>github</h3><br /> {/*isLoaded ? <UsersList users={githubUserResult} />: ''*/} <h3>gitLab</h3><br /> {/*isLoaded ? <UsersList users={gitlabUserResult} /> : ''*/} </div> ) } export default SearchBox;
问题原因
- Input为不受控组件:代码中的input只绑定了
onChange事件更新状态,但未绑定value={input},导致输入框实际值与React状态input不同步,首次点击时传递给接口的username是初始空值,第二次点击才拿到之前输入的内容。 - 异步代码写法混乱:混合使用
await和.then,且searchUser中未等待异步请求完成就设置isLoaded,状态更新逻辑混乱。 - setState异步特性误解:在
setGithubUserResult后直接console.log(githubUserResult),此时打印的是旧状态,无法查看更新后的数据。
修复方案
1. 将Input改为受控组件
给input添加value属性绑定到input状态,确保输入值与状态完全同步:
<input type="text" value={input} onChange={handleInputChange} />
2. 优化异步请求逻辑
统一使用async/await语法,避免混合then,同时在searchUser中等待所有请求完成后再更新加载状态:
const searchUser = async (e) => { e.preventDefault(); setError(null); // 重置错误状态 try { // 并行发起两个请求,等待全部完成 await Promise.all([ searchUserOnGithub(input), searchUserOnGitLab(input) ]); setIsloaded(true); } catch (err) { setError(err); } }
3. 重构单个请求函数
去掉多余的await和then混合写法,添加响应状态检查,完善错误处理:
const searchUserOnGithub = async (username) => { const res = await fetch(`/api/github/userinfo/${username}`, { method: "GET", headers: { "Content-Type": "application/json", } }); // 检查响应是否成功 if (!res.ok) { throw new Error(`GitHub请求失败: ${res.status}`); } const result = await res.json(); setGithubUserResult(result); } const searchUserOnGitLab = async (username) => { const res = await fetch(`/api/gitlab/userinfo/${username}`, { method: "GET", headers: { "Content-Type": "application/json", } }); if (!res.ok) { throw new Error(`GitLab请求失败: ${res.status}`); } const result = await res.json(); setGitlabUserResult(result); }
4. 正确查看状态更新结果
由于setState是异步的,直接在set之后打印无法获取新状态,使用useEffect监听状态变化:
useEffect(() => { console.log("GitHub用户结果更新:", githubUserResult); }, [githubUserResult]); useEffect(() => { console.log("GitLab用户结果更新:", gitlabUserResult); }, [gitlabUserResult]);
总结
核心问题是input未使用受控组件模式,导致状态与输入值不同步。修复后,输入内容会实时同步到React状态,首次点击就能传递正确的username发起请求,同时优化后的异步代码逻辑更清晰,错误处理更完善。
内容的提问来源于stack exchange,提问作者Yannick Makwenge
相关产品推荐
相关产品推荐

