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

ReactJS中getResult无法调用map函数问题求助

问题:渲染时getResult无法调用map函数

我在为API编写前端时遇到了问题:渲染时getResult无法调用map函数。已经把初始状态从null改为[],但问题依然存在。以下是Filter、GameTable和Game组件的代码,求解决思路。


组件代码

Filter组件

import React, { useState, useEffect } from 'react' 
import { useQuery } from 'react-query'; 
import gameService  from '../services/gameService' 
import GameTable from './GameTable' 
import '../App.css'

const Filter = () => {

const [getName, setGetName] = useState("")
const [getGenre, setGetGenre] = useState("")
//const [getPublisher, setGetPublisher] = useState("")
const [metadata,setMetadata] = useState([])

const [getResult, setGetResult] = useState([])

const fortmatResponse = (res) => {
  return JSON.stringify(res,null, 2);
}

const {isLoading: isLoadingGames, refetch: getAllGames} = useQuery("query-games",
  async() => {
    return await gameService.get("/games");
  },
  {
    enabled: false,
    onSuccess: (res) => {
        const result = {
          status : res.status + "-" + res.statusText,
          headers: res.headers,
          data: res.data,
        };
        setMetadata(fortmatResponse(result.data.metadata));
        setGetResult(fortmatResponse(result.data.games));
    },
    onError : (err) => {
      setGetResult(fortmatResponse(err.response?.data || err));
    },
  }
);

useEffect(() => {
  if (isLoadingGames) setGetResult("loading...");
},[isLoadingGames]);

function getAllData() {
  try{
    getAllGames();
  }catch(err) {
    setGetResult(fortmatResponse(err));
  }
}

const {isLoading: isLoadingGame, refetch: getGamesByName} = useQuery(
  "query-games-by-name",
  async () => {
    return await gameService.get(`/games?name=${getName}`);
  },
  {
    enabled: false,
    onSuccess: (res) => {
        const result = {
          status : res.status + "-" + res.statusText,
          headers: res.headers,
          data: res.data,
        };
        setMetadata(fortmatResponse(result.data.metadata));
        setGetResult(fortmatResponse(result.data.games));
    },
    onError : (err) => {
      setGetResult(fortmatResponse(err.response?.data || err));
    },
  }
);

useEffect(() => {
  if (isLoadingGame) setGetResult("loading...");
}, [isLoadingGame]);

function getDataByName() {
  if (getName) {
    try {
      getGamesByName();
    } catch (err) {
      setGetResult(fortmatResponse(err));
    }
  }
}

const {isLoading: isSearchingGame, refetch: findGamesByGenre} = useQuery(
  "query-games-by-genre",
  async () => {
    return await gameService.get(`/games?genre=${getGenre}`);
  },
  {
    enabled: false,
    onSuccess: (res) => {
      const result = {
        status : res.status + "-" + res.statusText,
        headers: res.headers,
        data: res.data,
      };
      setMetadata(fortmatResponse(result.data.metadata));
      setGetResult(fortmatResponse(result.data.games));
    },
    onError : (err) => {
      setGetResult(fortmatResponse(err.response?.data || err));
    },
  }
);

useEffect(() => {
  if (isSearchingGame) setGetResult("loading...");
}, [isSearchingGame]);

function getDataByGenre() {
  if (getGenre) {
    try {
      findGamesByGenre();
    } catch (err) {
      setGetResult(fortmatResponse(err));
    }
  }
}

const clearGetOutput =() => {
  setGetResult([]);
}
console.log(metadata)

return(
<div className='card'>
    <div className='card-header input-group-sm'> GET Request </div>
    <div className='card-body'>
      <div className='input-group input-group-sm'>
        <button className='btn btn-sm btn-primary' onClick={getAllData}>
          Get All
        </button>
        <input
          type="text"
          value={getName}
          onChange={(e) => setGetName(e.target.value)}
          className='form-control ml-2'
          placeholder='Name'
          />
        <div className='input-group-append'>
          <button className="btn btn-sm btn-primary" onClick={getDataByName}>
            Get by Name
          </button>
        </div>
        <input
            type="text"
            value={getGenre}
            onChange={(e) => setGetGenre(e.target.value)}
            className="form-control ml-2"
            placeholder="Genre"
            />
         <div className="input-group-append">
          <button className="btn btn-sm btn-primary" onClick={getDataByGenre}>
            Find By Genre
          </button>
        </div>
        <button className="btn btn-sm btn-warning ml-2" onClick={clearGetOutput}>
          Clear
        </button>
      </div>
      <GameTable games={getResult} />
      
    </div>
  </div>
  )
}

export default Filter;

GameTable组件

import React from 'react'
import Game from './Game'
import '../App.css'

const GameTable = ({games}) => {
    return (
        <div className="table-wrapper">
            <h2>Games</h2>
                <table className='fl-table'>
                <thead>
                    <tr>
                        <th> Name </th>
                        <th> Genre </th>
                        <th> Publisher </th>
                    </tr>
                </thead>
                <tbody>
                    {
                        games.map(game =>
                            <Game key={game.id} game={game} />
                        )
                    }     
                </tbody>
                </table>
        </div> 
    )
}
export default GameTable;

Game组件

import React from 'react'

const Game = ({game}) => {
    
    return (
        <tr>
            <td>{game.name}</td>
            <td>{game.genre}</td>
            <td>{game.publisher_name}</td>
        </tr>
    )
}
export default Game

解决思路

核心问题

你用fortmatResponse函数把API返回的游戏数组转成了JSON字符串,而字符串类型没有map方法,导致GameTable组件调用games.map时报错。同时你还把getResult设置过"loading..."字符串,进一步混淆了数据类型。

具体修改步骤

  1. 直接保存原始数组,不要转成字符串
    在所有useQuery的onSuccess回调里,去掉fortmatResponse对游戏数组的处理,直接赋值原始数组:

    // 原代码
    setGetResult(fortmatResponse(result.data.games));
    // 修改后
    setGetResult(result.data.games);
    
  2. 分离loading状态与数据状态
    不要把getResult设置为"loading...",而是利用react-query提供的isLoading状态单独处理加载提示:

    • 在Filter组件中把所有loading状态传给GameTable:
      <GameTable 
        games={getResult} 
        isLoading={isLoadingGames || isLoadingGame || isSearchingGame} 
      />
      
    • 修改GameTable组件,根据loading状态显示对应内容:
      const GameTable = ({games, isLoading}) => {
          if (isLoading) return <div>loading...</div>;
          // 如果数组为空,也可以加个空状态提示
          if (!games.length) return <div>暂无游戏数据</div>;
      
          return (
              <div className="table-wrapper">
                  <h2>Games</h2>
                  <table className='fl-table'>
                  {/* 原有表格代码 */}
                  </table>
              </div> 
          )
      }
      
  3. 分离错误状态
    不要把错误信息存到getResult里,单独用一个状态管理错误:

    // 在Filter组件顶部新增状态
    const [error, setError] = useState(null);
    
    // 在所有useQuery的onError回调里修改
    setError(err.response?.data || err);
    // 在Filter组件的return里添加错误提示
    {error && <div style={{color: 'red'}}>{JSON.stringify(error)}</div>}
    
  4. 清理无用代码
    删除之前用来设置loading文本的useEffect,因为已经通过react-query的isLoading状态处理加载逻辑。


内容的提问来源于stack exchange,提问作者Can Yolal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:15:27