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

如何在React中用reduce与Promise.all实现多组数据高效展示

Hey Dave, great call wanting to clean up this code—duplicating the TopAnime rendering isn't ideal, and you're right that reduce can help here. Let's walk through fixing your reduce usage first, then refactor the component to reuse that TopAnime component properly.

First: Fix the reduce Usage

Your current reduce is trying to add arrays together with acc + anime, which converts everything to messy strings (not what we want!). Instead, we need to either concatenate the top arrays from each API response, or use reduce to build a structured list of categories (since you want to display TV and Airing separately with their own headers).

For category-structured data (perfect for your use case), here's how to use reduce correctly:

const topCategories = data.reduce((acc, response, index) => {
  // Match the order of your API calls to the headers you want
  const sectionTitles = ["Top TV", "Top Airing"];
  acc.push({
    title: sectionTitles[index],
    items: response.top.slice(0, 6) // Grab top 6 here to avoid repeating it later
  });
  return acc;
}, []);

Second: Refactor State & Data Fetching

Let's update your component state to hold this structured category array instead of two separate arrays. We'll also simplify the getData method by leaning fully into async/await (no more nested then calls!):

class HomePage extends Component {
  // New state structure: holds an array of category objects
  state = { topAnimeCategories: [] }

  async getData() {
    const api = "https://api.jikan.moe/v3";
    const urls = [
      `${api}/top/anime/1/tv`,
      `${api}/top/anime/1/airing`
    ];

    try {
      // Fetch all API responses in parallel
      const responses = await Promise.all(urls.map(url => fetch(url)));
      // Convert all responses to JSON in parallel
      const data = await Promise.all(responses.map(resp => resp.json()));
      
      // Build our category array with reduce
      const topCategories = data.reduce((acc, response, index) => {
        const sectionTitles = ["Top TV", "Top Airing"];
        acc.push({
          title: sectionTitles[index],
          items: response.top.slice(0, 6)
        });
        return acc;
      }, []);

      this.setState({ topAnimeCategories: topCategories });
    } catch (err) {
      console.error("There was an error fetching anime data:", err);
    }
  }

  componentDidMount() {
    this.getData();
  }

Third: Reuse the TopAnime Component (No More Duplication!)

Now we can loop through our topAnimeCategories state to render each section once. Also, note we replaced splice(0,6) with slice(0,6)—splice modifies the original array (which can cause unexpected state bugs), while slice safely returns a new array.

render() {
    return (
      <HomeWrapper>
        {this.state.topAnimeCategories.map((category) => (
          <div key={category.title}>
            <h2>{category.title}</h2>
            <TopAnime>
              {category.items.map((ani) => (
                <div key={ani.mal_id}>
                  <img src={ani.image_url} alt={`${ani.title} poster`} />
                  <h3>{ani.title}</h3>
                </div>
              ))}
            </TopAnime>
          </div>
        ))}
      </HomeWrapper>
    )
  }
}

Bonus: Scalability Win

If you ever want to add more sections (like Top Movies or Top OVAs), you just need to:

  1. Add a new URL to the urls array
  2. Add a corresponding title to the sectionTitles array
    No need to duplicate any rendering code—your map loop will handle the rest automatically.

内容的提问来源于stack exchange,提问作者Dave.Q

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:29:29