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

React useState Hooks处理JSON数据时出现嵌套数组而非单数组问题

React useState设置状态后结构异常问题

我在React应用开发时遇到状态变量设置异常问题:我在useEffect Hook中调用异步函数,通过axios向Express服务端发起请求拉取JSON数据,打印请求返回的pulledOutages数据,输出为符合预期的单数组结构,但调用setAllOutages设置状态后,打印allOutages发现其变为嵌套数组结构,未与请求返回数据保持一致。此前我用类似写法调用第三方API时状态设置正常,想了解正确的状态变量设置方式是什么,以下是我的代码和终端输出截图:

import { MapContainer, TileLayer, Marker, Popup, Circle } from "react-leaflet";
import React, { useState, useEffect } from "react";
import mockData from "./testData/MOCK_DATA.json";
import axios from "axios";
import outageData from "./testData/outageData.json";

function OutageIndicator({ outage }) {
  //this component renders the markers with corresponding lat and long values calculated by the geocodify api.
  const [coords, setCoords] = useState();

  useEffect(() => {
    async function resolveLocation() {
      const resp = await axios.get(
        "https://api.geocodify.com/v2/geocode/json?api_key=mykey&q=" +
          outage.outage_street +
          ", " +
          outage.outage_city +
          ", Michigan, USA"
      );
      const [lng, lat] = resp.data.response.bbox;
      setCoords({ lng, lat });
    }
    resolveLocation();
  }, [outage]);

  return !coords ? (
    "Loading"
  ) : (
    <Marker position={[coords.lat, coords.lng]}>
      <Popup>
        {outage.service_type} {outage.service_name}
      </Popup>
    </Marker>
  );
}

function OutageMap() {
  //This is where the map page will be rendered.
  const [allOutages, setAllOutages] = useState();
  useEffect(() => {
    async function fetchOutages() {
      const resp = await axios.get("/outages");
      const pulledOutages = resp.data.outages;
      //console.log(pulledOutages); //This outputs a single array that is pulled from the api call
      setAllOutages({ pulledOutages });
      console.log(allOutages); //this outputs an array of arrays that are similar to pulledOutages
    }
    fetchOutages();
  });

  return (
    <MapContainer center={[38.89, -77.059]} zoom={13} scrollWheelZoom={true}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      //outageData below is dummy data that was hard coded. This would change to allOutages once the state variable is set correctly.
      {outageData.outages.map((mock) => (
        <OutageIndicator outage={mock} />
      ))}
    </MapContainer>
  );
}

export default OutageMap;

终端显示allOutages状态变量


问题根源

  • 语法错误:setAllOutages({ pulledOutages })使用了对象简写语法,实际给状态赋值的是{ pulledOutages: [接口返回数组] }格式的对象,而非直接赋值数组本身,导致状态结构不符合预期。
  • 状态更新异步特性:React的状态更新是批量异步执行的,调用setAllOutages后立刻打印当前作用域内的allOutages,拿到的是本次渲染的旧状态值,并非更新后的值。
  • useEffect缺少依赖:当前useEffect未设置依赖数组,组件每渲染一次就会重新触发一次接口请求,会出现无限重复请求的问题。

修复方案

  1. 修正状态赋值语法,去掉包裹pulledOutages的花括号,直接传入数组本身
  2. 给useEffect添加空数组作为依赖,让接口请求仅在组件挂载时触发一次
  3. 给allOutages设置空数组作为初始值,避免后续遍历时报undefined错误
  4. 若要验证更新后的状态值,可新增useEffect监听allOutages变化后再打印

修复后代码片段

function OutageMap() {
  // 初始化空数组作为默认值
  const [allOutages, setAllOutages] = useState([]);
  // 空依赖数组:仅组件挂载时执行一次请求
  useEffect(() => {
    async function fetchOutages() {
      const resp = await axios.get("/outages");
      const pulledOutages = resp.data.outages;
      // 直接传入数组,不要加花括号
      setAllOutages(pulledOutages);
    }
    fetchOutages();
  }, []);

  // 监听allOutages变化,打印更新后的状态
  useEffect(() => {
    console.log(allOutages);
  }, [allOutages]);

  return (
    <MapContainer center={[38.89, -77.059]} zoom={13} scrollWheelZoom={true}>
      <TileLayer
        attribution='&copy; OpenStreetMap contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      {/* 直接遍历allOutages渲染标记,新增key避免React警告 */}
      {allOutages.map((outageItem, index) => (
        <OutageIndicator key={index} outage={outageItem} />
      ))}
    </MapContainer>
  );
}

内容的提问来源于stack exchange,提问作者Shafi Kamal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:39:04