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

React+Redux动态路由数据传递异常:Artists组件接收空数组

问题描述

从后端3个不同接口获取数据,目标是在动态路由组件中展示所有数据,但Artists.js始终接收空数组。

已尝试方案:

  • 使用useNavigate传递数据
  • 使用Link传递数据
  • 使用Redux Toolkit传递数据(刚接触Redux,代码可能存在问题)

排查发现渲染时机问题:添加条件渲染后,Artists组件第二次渲染时控制台能显示正确数据,但页面一直停留在“loading”状态;尝试在条件渲染后映射数据,刷新页面后渲染内容消失。

补充接口返回结构:

  • 接口返回示例:{artists: {…}, playlists: {…}, tracks: {…}}
  • artists结构:artists: {total: 13, artists: Array(13)}
  • 单个artist对象:{name: 'Aborted', id: '1XRhUgCyzIdeT8d9KMfeDR', image_url: 'https://i.scdn.co/image/ab6761610000e5eb457a41afcb20ec257fce22d4', popularity: 39, genres: Array(8)}

问题分析与修复方案

核心问题

  1. Redux数据赋值错误:接口返回的artists是包含total和artists数组的嵌套对象,但代码直接将整个对象赋值给Redux状态,导致组件中拿到的不是数组,length判断失效。
  2. Loading状态未更新:isLoading初始化为true后无逻辑切换为false,组件一直卡在loading分支。
  3. 路由冲突:/:genre和/:artist都是动态参数路由,会导致匹配优先级混乱(比如访问艺术家页面时可能匹配到genre路由)。
  4. 数据加载与路由跳转时机不匹配:点击Link时先跳转路由再加载数据,组件初始化时Redux还未存入数据。

具体修复步骤

1. 修正Redux数据赋值逻辑

在Genres.js的handleClick中,解构接口返回的嵌套数组:

// Genres.js
.then(([artistRes, playlistRes, trackRes]) => {
  // 提取接口返回中的实际数组
  dispatch(setData({ 
    artists: artistRes.artists.artists, 
    playlists: playlistRes.playlists.playlists, 
    tracks: trackRes.tracks.tracks 
  }));
})

2. 修复Artists组件的Loading状态

使用useEffect监听Redux中artists的变化,动态更新加载状态:

// Artists.js
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useSelector } from 'react-redux';

function Artists() {
  const navigate = useNavigate();
  const artists = useSelector((state) => state.spotifyData.artists);
  const [isLoading, setIsLoading] = useState(true);

  // 监听artists变化,数据就绪后结束加载
  useEffect(() => {
    if (artists.length > 0) {
      setIsLoading(false);
    }
  }, [artists]);

  // 加载状态判断:先显示loading,数据为空时显示无数据
  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (artists.length === 0) {
    return <div>No artists found</div>;
  }

  // ... 其余点击事件和渲染逻辑不变
}

3. 解决路由冲突

调整路由结构,给动态路由添加明确前缀避免冲突:

// App.js
function App() {
  return (
    <Routes>
      <Route path='/' element={<Genres />} />
      {/* 给艺术家路由添加前缀 */}
      <Route path='/artist/:artist' element={<TopTracks />} />
      {/* 给流派路由添加前缀 */}
      <Route path='/genre/:genre' element={<Results />} />
    </Routes>
  );
}

同步修改跳转路径:

  • Genres.js中的Link:<Link to={/genre/${genre}} onClick={() => handleClick(genre)}>{genre}</Link>
  • Artists.js中的navigate:navigate(/artist/${artist.name}, { state: { data } });

4. 优化数据加载与跳转时机(可选)

避免先跳转后加载数据,改为加载完成后手动导航:

// Genres.js
import { useNavigate } from "react-router-dom";

function Genres() {
  const navigate = useNavigate();
  // ... 其余状态和useEffect不变

  function handleClick(genre) {
    const query_params = { genre: genre };
  
    Promise.all([/* 三个fetch请求 */])
      .then((responses) => Promise.all(responses.map(res => res.json())))
      .then(([artistRes, playlistRes, trackRes]) => {
        dispatch(setData({ 
          artists: artistRes.artists.artists, 
          playlists: playlistRes.playlists.playlists, 
          tracks: trackRes.tracks.tracks 
        }));
        // 数据加载完成后再跳转
        navigate(`/genre/${genre}`);
      })
      .catch(error => console.log(error));
  }

  // 将Link改为按钮,避免默认跳转
  return (
    <div>
      <div className="genre-list-container">
        <ul className="genre-list">
          {genres.map((genre) => (
            <li className="genre" key={genre}>
              <button onClick={() => handleClick(genre)}>{genre}</button>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

额外注意事项

  • 刷新页面时Redux数据会丢失(内存存储特性),若需支持刷新,可考虑将数据存入localStorage,或在Results组件中根据路由参数重新请求数据。
  • 检查X-CSRFToken的处理逻辑,确保后端能正常接收请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:29:52