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

React使用useState存储过滤后的数组传入Modal时提示变量未定义

问题描述

我为即将到来的NFL赛季制作了一个JSON文件,当前组件已经实现了可正常运行的fetch方法获取数据,存储数据的变量命名为squads。现在需要实现点击按钮过滤出选中球队的赛程,并将其展示在Modal中,本示例中的按钮为硬编码实现。Modal组件本身运行正常,且Modal主体部分预留了{props.children}用于接收传入的数据。

我尝试使用useState将过滤得到的球队数据赋值给selectedTeam变量,运行后收到了变量未定义的错误提示,代码如下:

import React, { useState, useEffect } from "react";
import Modal from "./Components/Modal";

export default function App() {
  const [show, setShow] = useState(false);
  const [title, setTitle] = useState("");
  const [squads, setSquads] = useState([]);
  const [modalTitleBackground, setModalTitleBackground] = useState("");
  const [image, setImage] = useState("");
  const [selectedTeam, setSelectedTeam] = useState([]);

  const url = "../nfl2021.json";

  const fetchData = async () => {
    try {
      const response = await fetch(url);
      const data = await response.json();
      setSquads(data.teams);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);

  const filterTeam = (team) => {
    setSelectedTeam(squads.filter((squad) => squad.name === team));
    console.log(selectedTeam);
    setTitle(selectedTeam[0].name);
    setModalTitleBackground(selectedTeam[0].topBG);
    setImage(`./images/${selectedTeam[0].img}`);
    setShow(true);
  };

  return (
    <div className="App">
      <button onClick={() => filterTeam("New England Patriots")}>
        Show Modal
      </button>
      <button onClick={() => filterTeam("Green Bay Packers")}>
        Show Modal 2
      </button>
      <button onClick={() => filterTeam("Cincinnati Bengals")}>
        Show Modal 3
      </button>
      <Modal
        image={image}
        title={title}
        backgroundColor={modalTitleBackground}
        onClose={() => setShow(false)}
        show={show}
      >
        <p>
          This is the modal body using props.children in the modal component.
        </p>
        <p>The {title} 2021 schedule.</p>

        {selectedTeam[0].schedule.map((schedule, index) => {
          return (
            <p>
              Week {index + 1}: The {selectedTeam[0].nickname} play the{" "}
              {selectedTeam[0].schedule[index].opponent}.
            </p>
          );
        })}
      </Modal>
    </div>
  );
}

错误原因

React的setState是异步更新的,调用setSelectedTeam后,当前函数作用域内的selectedTeam还是更新前的初始空数组,取selectedTeam[0]会得到undefined,直接访问属性就会触发报错。同时初始渲染时selectedTeam是空数组,Modal内直接访问selectedTeam[0]也会报错。

修复方案

  1. 将filter筛选后的结果存到临时变量,后续更新其他状态直接使用该临时变量,不读取刚更新的state
  2. 将selectedTeam初始值改为null,渲染赛程时加条件判断,避免空值报错
  3. 优化赛程渲染逻辑,直接使用map方法返回的赛程对象,无需重复取下标

修正后代码

import React, { useState, useEffect } from "react";
import Modal from "./Components/Modal";

export default function App() {
  const [show, setShow] = useState(false);
  const [title, setTitle] = useState("");
  const [squads, setSquads] = useState([]);
  const [modalTitleBackground, setModalTitleBackground] = useState("");
  const [image, setImage] = useState("");
  // 初始值改为null,方便判断是否有选中球队
  const [selectedTeam, setSelectedTeam] = useState(null);

  const url = "../nfl2021.json";

  const fetchData = async () => {
    try {
      const response = await fetch(url);
      const data = await response.json();
      setSquads(data.teams);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);

  const filterTeam = (team) => {
    // 筛选结果存到临时变量
    const matchedTeam = squads.filter(squad => squad.name === team)[0];
    setSelectedTeam(matchedTeam);
    // 直接用临时变量更新其他状态
    setTitle(matchedTeam.name);
    setModalTitleBackground(matchedTeam.topBG);
    setImage(`./images/${matchedTeam.img}`);
    setShow(true);
  };

  return (
    <div className="App">
      <button onClick={() => filterTeam("New England Patriots")}>
        Show Modal
      </button>
      <button onClick={() => filterTeam("Green Bay Packers")}>
        Show Modal 2
      </button>
      <button onClick={() => filterTeam("Cincinnati Bengals")}>
        Show Modal 3
      </button>
      <Modal
        image={image}
        title={title}
        backgroundColor={modalTitleBackground}
        onClose={() => setShow(false)}
        show={show}
      >
        <p>
          This is the modal body using props.children in the modal component.
        </p>
        <p>The {title} 2021 schedule.</p>
        {/* 加条件判断,有选中球队才渲染赛程 */}
        {selectedTeam && selectedTeam.schedule.map((schedule, index) => (
          <p key={index}>
            Week {index + 1}: The {selectedTeam.nickname} play the {schedule.opponent}.
          </p>
        ))}
      </Modal>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者John G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:45:03