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='© <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;

问题根源
- 语法错误:
setAllOutages({ pulledOutages })使用了对象简写语法,实际给状态赋值的是{ pulledOutages: [接口返回数组] }格式的对象,而非直接赋值数组本身,导致状态结构不符合预期。 - 状态更新异步特性:React的状态更新是批量异步执行的,调用setAllOutages后立刻打印当前作用域内的allOutages,拿到的是本次渲染的旧状态值,并非更新后的值。
- useEffect缺少依赖:当前useEffect未设置依赖数组,组件每渲染一次就会重新触发一次接口请求,会出现无限重复请求的问题。
修复方案
- 修正状态赋值语法,去掉包裹
pulledOutages的花括号,直接传入数组本身 - 给useEffect添加空数组作为依赖,让接口请求仅在组件挂载时触发一次
- 给
allOutages设置空数组作为初始值,避免后续遍历时报undefined错误 - 若要验证更新后的状态值,可新增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='© 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
相关产品推荐
相关产品推荐

