You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
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;
现存问题

目前遇到两个异常问题:

  1. 在搜索栏输入内容后点击搜索图标触发提交,虽然最终能正确渲染包详情,但接口请求获取数据的过程中,Loader加载组件未正常显示;
  2. 触发表单提交操作时,页面渲染的是默认值react对应的包详情,而非用户在搜索栏输入的目标包名对应的内容。
    作为React初学者,不确定当前的状态管理写法是否正确,需要对应问题的解决方案。
问题原因与修复方案

问题1:Loader加载组件不显示

  • 原因:loading状态仅在组件初始化时设为true,第一次请求完成后被置为false,后续input变化触发重新请求时,没有在请求发起前将loading重置为true,所以加载状态不会触发。
  • 修复:在请求函数开头先把loading设为true,无论请求成功失败,最终都要把loading设为false。

问题2:提交后一直渲染默认react包内容

  • 原因:
    1. 表单提交默认会触发页面刷新,没有阻止该默认行为,页面刷新后React状态会重置回初始值react
    2. 搜索图标同时绑定了onClick事件,和表单的onSubmit会重复触发提交逻辑,加上setInput后立刻清空输入框ref的值,很容易拿到空值
  • 修复:
    1. 给提交事件加preventDefault()阻止表单默认刷新
    2. 移除搜索图标上多余的onClick事件,提交逻辑统一由表单onSubmit接管,避免重复触发;先获取输入框的值校验后再更新状态,最后清空输入框。
修复后核心代码
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:42:40