React OnClick事件异常:Loader不显示、提交取值错误
问题背景
我开发了一个包含search bar的navbar component以及main page component,预期实现逻辑为:在搜索栏输入npm包名后,调用api.npms.io接口获取对应包的详情信息,并在主页面组件渲染展示。
相关组件代码如下:
App.jsx
function App() { const [input, setInput] = useState('react'); return ( <div className="App"> <Navbar setInput={setInput} /> <div className="sections"> <Main input={input} /> </div> </div> ); } export default App;
Navbar 组件
function Navbar({ setInput }) { const inputRef = useRef(); const submitHandler = () => { setInput(inputRef.current.value); inputRef.current.value = ''; }; return ( <div className="Navbar" id="Navbar"> <div className="logo"> <img src={logo} alt="logo" /> </div> <div className="line"></div> <form onSubmit={submitHandler}> <div className="search"> <img src={search} alt="search" onClick={submitHandler} /> <input placeholder={'Search for a NPM package'} name="name" type="text" ref={inputRef} id="name" ></input> </div> </form> </div> ); } export default Navbar;
Main.jsx
function Main({ input }) { const [packageInfo, setPackageInfo] = useState(null); const [loading, setLoading] = useState(true); const fetchPackageInfo = async (input) => { const response = await fetch(`https://api.npms.io/v2/package/${input}`); const data = await response.json(); setPackageInfo(data); setLoading(false); }; useEffect(() => { fetchPackageInfo(input); }, [input]); return ( <div> {loading ? ( <Loader /> ) : ( <div className="Main" id="Main"> <div className="row"> <Summary heading={packageInfo.collected.metadata.name} version={packageInfo.collected.metadata.version} description={packageInfo.collected.metadata.description} license={packageInfo.collected.metadata.license} npm={packageInfo.collected.metadata.links.npm} github={packageInfo.collected.metadata.links.homepage} downloads={Math.trunc( packageInfo.evaluation.popularity.downloadsCount ).toLocaleString()} keywords={packageInfo.collected.metadata.keywords.join(', ')} /> </div> </div> )} </div> ); } export default Main;
现存问题
目前遇到两个异常问题:
- 在搜索栏输入内容后点击搜索图标触发提交,虽然最终能正确渲染包详情,但接口请求获取数据的过程中,Loader加载组件未正常显示;
- 触发表单提交操作时,页面渲染的是默认值
react对应的包详情,而非用户在搜索栏输入的目标包名对应的内容。
作为React初学者,不确定当前的状态管理写法是否正确,需要对应问题的解决方案。
问题原因与修复方案
问题1:Loader加载组件不显示
- 原因:
loading状态仅在组件初始化时设为true,第一次请求完成后被置为false,后续input变化触发重新请求时,没有在请求发起前将loading重置为true,所以加载状态不会触发。 - 修复:在请求函数开头先把
loading设为true,无论请求成功失败,最终都要把loading设为false。
问题2:提交后一直渲染默认react包内容
- 原因:
- 表单提交默认会触发页面刷新,没有阻止该默认行为,页面刷新后React状态会重置回初始值
react - 搜索图标同时绑定了
onClick事件,和表单的onSubmit会重复触发提交逻辑,加上setInput后立刻清空输入框ref的值,很容易拿到空值
- 表单提交默认会触发页面刷新,没有阻止该默认行为,页面刷新后React状态会重置回初始值
- 修复:
- 给提交事件加
preventDefault()阻止表单默认刷新 - 移除搜索图标上多余的
onClick事件,提交逻辑统一由表单onSubmit接管,避免重复触发;先获取输入框的值校验后再更新状态,最后清空输入框。
- 给提交事件加
修复后核心代码
Navbar 组件提交逻辑
const submitHandler = (e) => { // 阻止表单默认刷新行为 e.preventDefault(); const searchValue = inputRef.current.value.trim(); if(!searchValue) return; setInput(searchValue); // 状态更新后再清空输入框 inputRef.current.value = ''; }; // 移除img标签上的onClick绑定,避免重复触发 <img src={search} alt="search" />
Main.jsx 请求逻辑
const fetchPackageInfo = async (input) => { // 请求发起前开启加载状态 setLoading(true); try { // 对包名做编码,避免特殊字符导致请求异常 const response = await fetch(`https://api.npms.io/v2/package/${encodeURIComponent(input)}`); if(!response.ok) throw new Error('包信息获取失败'); const data = await response.json(); setPackageInfo(data); } catch (err) { console.error(err); setPackageInfo(null); } finally { // 无论请求成功失败,都关闭加载状态 setLoading(false); } };
内容的提问来源于stack exchange,提问作者Rohith Nambiar
相关产品推荐
相关产品推荐

