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

React调用fetch API后setState未即时更新问题排查

问题根源

你的代码有4个核心错误,导致状态更新不符合预期:

  • useEffect 回调的参数写法完全错误。useEffect 执行回调时不会传入任何状态参数,你写在形参里的CP、ListVille是和组件状态完全无关的未定义局部变量,实际请求的地址是http://localhost:3000//api/1.0/getCommunes/undefined,根本拿不到对应邮编的城镇数据。
  • 省略了useEffect的依赖数组。不传依赖数组时,effect会在每一次组件渲染完成后全量执行:输入CP触发重渲染→执行effect发请求→请求返回调用setList触发重渲染→再次执行effect发请求,形成无限请求循环,状态会被重复覆盖,永远无法稳定。你想要CP变化时触发请求,只需要把CP加入依赖数组即可,不需要完全省略依赖数组。
  • 调用setList后立刻打印ListVille拿不到新值。React的状态更新是异步批处理机制,当前执行上下文中的ListVille还是本轮渲染的旧值,必须等组件完成下一次重渲染后,才能获取到更新后的状态值。
  • ListVille没有设置合法初始值。你给ListVille的初始值是undefined,如果渲染时直接访问ListVille[0]这类属性,会直接抛出Cannot read properties of undefined的运行时错误。
修正后代码
import React, {useEffect, useState} from 'react';
import {Navigate} from 'react-router-dom'
import Entete from './MEP/entete'

function Localisation() {
  const [CP, setCP]= React.useState('');
  const [city, setCity]= React.useState('');
  // 给ListVille设置空数组初始值,避免访问属性时报错
  const [ListVille, setList]= React.useState([]);
  const [goToExploit, setGoToExploit] = useState(false)

  useEffect ( () => {
    // CP为空时不发送无效请求
    if (!CP.trim()) return
    // 修正接口地址的双斜杠问题,直接从组件闭包读取最新的CP值
    fetch(`http://localhost:3000/api/1.0/getCommunes/${CP}`)
      .then( (response) => {
        console.log('请求响应对象:', response)
        return response.json()
      })
      .then(resData =>{
        setList(resData)
        console.log('接口返回的城镇数据:', resData)
      }) 
  // 依赖数组仅传入CP,只有CP变化时才会重新执行请求逻辑
  }, [CP])

  // 如需监听ListVille的更新,单独写effect监听即可
  useEffect(() => {
    console.log('当前ListVille最新状态:', ListVille)
  }, [ListVille])

  function handleSubmit(event) {
    event.preventDefault()
    setGoToExploit(true)
  }

  if(goToExploit) {
      return <Navigate push to={`/exploitation`} />
  }

  function handleChange(event) {
    const inputCP = event.target.value.trim()
    setCP(inputCP)      
 }

  return (
    <div>
      <Entete titre="Localisation"/>

      <form onSubmit={handleSubmit}>
        <div className='titre'> Saisissez votre code postal {CP}</div>
        <input 
        className='input'
        value={CP}
        onChange={handleChange}
        placeholder='Code Postal'
        type='text'
        required/>
        {/* 加可选链操作符兼容数据未返回的场景,避免报错 */}
        <div className='paragraphe'> Test {CP==='41160' ? ListVille[0]?.key ?? '暂无匹配城镇' : '请输入邮编'}</div>
        <div className='centrer'>
          <button type='submit' className='validation'> Valider </button>
        </div>
      </form>
    </div>
  );
}

export default Localisation;

修正后逻辑:输入邮编时CP更新,触发effect发请求拉取对应城镇数据,数据返回后更新ListVille,组件自动重渲染展示最新数据,不会出现无限循环,也不会有状态不更新的问题。

内容的提问来源于stack exchange,提问作者Aliénor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:51:17