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

窗口Resize时API获取的Books组件重复渲染问题排查

问题分析与解决方案

你的Home组件在窗口resize时的重复渲染和服务端逻辑、请求处理完全无关——请求仅在组件挂载时执行一次(useEffect空依赖数组保证这点)。下面是具体原因和优化方案:

原因拆解

  1. React默认行为:浏览器窗口尺寸变化时,React会触发全局重渲染检查,你的组件会因响应式样式(如md:mt-3这类Tailwind类)或父组件重渲染而跟着重新渲染。
  2. 初始状态更新冗余:当前代码中两次setState会触发两次初始渲染,但这是初始化阶段的正常现象,和resize无关。
  3. 组件未做渲染优化:未使用React的渲染优化API,导致任何全局重渲染触发(比如resize)都会让组件重复渲染。

具体修复方案

1. 修正无效错误提示逻辑

你代码中else分支直接写<p>...</p>完全无效,因为这只是返回JSX却没有渲染到页面,改成在return中处理空状态:

import React, { useState, useEffect } from 'react';
import CardGroup from '../components/CardGroup';
import Banner from '../components/Banner';

export default function Home() {
  const [recommendedBooks, setRecommendedBooks] = useState([]);
  const [sciFiClassicsBooks, setSciFiClassicsBooks] = useState([]);

  useEffect(() => {
    fetch('http://localhost:5000')
      .then(response => response.json())
      .then(data => {
        const recommendedCategory = data.allBooks.find(category => category.category === 'Recommended');
        const sciFiClassicsCategory = data.allBooks.find(category => category.category === 'SciFi Classics');

        // 使用可选链简化逻辑,避免冗余判断
        setRecommendedBooks(recommendedCategory?.books || []);
        setSciFiClassicsBooks(sciFiClassicsCategory?.books || []);
      })
      .catch(error => {
        console.error('Error fetching data:', error.message);
      });
  }, []);

  return (
    <div className="md:mt-3 lg:mt-8">
      <Banner />
      {recommendedBooks.length > 0 ? (
        <CardGroup key="Recommended" title="Recommended" books={recommendedBooks} />
      ) : (
        <p>Recommended category not found</p>
      )}
      {sciFiClassicsBooks.length > 0 ? (
        <CardGroup key="SciFi Classics" title="SciFi Classics" books={sciFiClassicsBooks} />
      ) : (
        <p>Scifi classic category not found</p>
      )}
    </div>
  );
}

2. 阻止不必要的重渲染

用React.memo包裹Home组件,让组件仅在props或状态变化时才重新渲染:

// 修改组件导出部分
export default React.memo(function Home() {
  // 原组件逻辑不变
});

如果CardGroup组件也存在同类问题,同样用React.memo包裹它:

// CardGroup组件示例
export default React.memo(function CardGroup(props) {
  // 原组件逻辑不变
});

3. 服务端代码优化(可选)

虽然服务端不是当前问题的根源,但可以优化书籍查询逻辑,避免嵌套循环:

const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 5000;

app.use(cors());
app.use('/data', express.static(path.join(__dirname, '..', 'client', 'src', 'data')));

const allBooks = [/* 原数组内容不变 */];

// 预先构建ID映射表,提升查询效率
const bookIdMap = new Map();
allBooks.forEach(category => {
  category.books.forEach(book => {
    bookIdMap.set(book.id, book);
  });
});

app.get('/', (_, res) => {
  res.json({ allBooks });
});

app.get('/book/:id', (req, res) => {
  const bookId = parseInt(req.params.id);
  const book = bookIdMap.get(bookId);

  if (book) {
    res.json({ book });
  } else {
    res.status(404).json({ error: 'Book not found' });
  }
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:29:51