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

React中基于useState状态的API调用的正确实现方式

正确发起基于useState状态的API调用的方法

当依赖useState管理的状态发起API调用时,直接在函数中使用状态值可能因为闭包捕获旧值的问题,拿不到最新状态。你给出的示例里,loadCountryData1存在这样的风险,loadCountryData2虽然能拿到最新值,但属于滥用setState回调的取巧写法,不符合官方规范。以下是几种官方推荐的正确实现方式:

1. 用useRef跟踪最新状态

useRef的.current属性不受闭包影响,始终保存最新的状态值,适合需要确保拿到最新状态的场景:

import { useState, useRef } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [selected, setSelected] = useState(null);
  const selectedRef = useRef(null); // 创建ref跟踪最新选中值

  const handleSelect = (e) => {
    const value = e.currentTarget.value;
    setSelected(value);
    selectedRef.current = value; // 同步更新ref的值
  };

  const [countryData, setCountryData] = useState(null);

  const loadCountryData = () => {
    // 使用ref中的最新值发起请求
    axios.get(`https://restcountries.com/v3.1/name/${selectedRef.current}`)
      .then((response) => setCountryData(response.data));
  };

  return (
    <div className="App">
      <div className="container">
        <select value={selected} onChange={handleSelect}>
          <option value={null}>Select country</option>
          <option value="india">India</option>
          <option value="usa">USA</option>
          <option value="germany">Germany</option>
        </select>
        <button onClick={loadCountryData} disabled={selected === null}>
          Load
        </button>
      </div>
      <div>
        {countryData !== null && (
          <pre>{JSON.stringify(countryData, null, 4)}</pre>
        )}
      </div>
    </div>
  );
}

2. 事件触发时直接传递当前状态值

如果是通过按钮点击手动触发API调用,可以在点击回调中直接把当前状态作为参数传入。由于组件每次状态更新后都会重新渲染,点击回调会捕获最新的状态值:

// 修改按钮的onClick回调,直接传入当前selected
<button onClick={() => loadCountryData(selected)} disabled={selected === null}>
  Load
</button>

// 对应的loadCountryData函数接收参数
const loadCountryData = (currentSelected) => {
  axios.get(`https://restcountries.com/v3.1/name/${currentSelected}`)
    .then((response) => setCountryData(response.data));
};

3. 用useEffect监听状态变化(自动触发场景)

如果需求是状态更新后自动加载数据,而非手动点击按钮,useEffect是最标准的实现方式。React会确保useEffect的回调在状态更新后执行,且使用最新的状态值:

import { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [selected, setSelected] = useState(null);

  const handleSelect = (e) => {
    setSelected(e.currentTarget.value);
  };

  const [countryData, setCountryData] = useState(null);

  // 监听selected变化,自动发起请求
  useEffect(() => {
    if (!selected) return; // 未选中时不执行

    const fetchCountryData = async () => {
      try {
        const response = await axios.get(`https://restcountries.com/v3.1/name/${selected}`);
        setCountryData(response.data);
      } catch (err) {
        console.error("加载数据失败:", err);
      }
    };

    fetchCountryData();
  }, [selected]); // 依赖项为selected,状态变化时触发

  return (
    <div className="App">
      <div className="container">
        <select value={selected} onChange={handleSelect}>
          <option value={null}>Select country</option>
          <option value="india">India</option>
          <option value="usa">USA</option>
          <option value="germany">Germany</option>
        </select>
      </div>
      <div>
        {countryData !== null && (
          <pre>{JSON.stringify(countryData, null, 4)}</pre>
        )}
      </div>
    </div>
  );
}

补充说明

  • 为什么loadCountryData1不安全:JavaScript闭包会捕获函数定义时的状态值,若在setSelected后立即调用该函数(比如快速操作或同步调用),此时组件还未重新渲染,函数内的selected仍是旧值,导致API调用使用错误参数。
  • 为什么loadCountryData2不推荐:setState的回调函数设计目的是计算新状态,而非执行副作用(如API调用),这种写法违反React设计规范,代码可读性差且易引发维护问题。

内容的提问来源于stack exchange,提问作者Bob Sacamano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:15:10