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

React中useEffect结合axios获取书籍数据遇循环及刷新状态丢失问题

书籍首页数据加载问题排查与解决

问题描述

  • 不给useEffect加空依赖数组[]时,组件陷入无限循环;
  • 添加空依赖数组后,首次加载正常,但刷新页面后页面为空,state值丢失;
  • 疑问:在useEffect中使用setState是否有问题?为什么刷新页面后useEffect不生效?

原组件代码

import React, { useEffect, useState } from "react";
import axios from "axios"
import { useNavigate } from "react-router-dom";
import BookItem from "../bookItem/bookItem";
import './Home.css'

function HomePage() {
    const [books, setBooks] = useState([])
    const [comedyBooks, setComedy] = useState([])
    const [sportBooks, setSport] = useState([])
    const [actionBooks, setAction] = useState([])


    let navigate = useNavigate();

//option 1
    // useEffect(() => {
    //     axios.get('http://127.0.0.1:3000/books')
    //         .then(res => {
    //             setBooks(res.data.data.books)
    //             let comedyBook = []

    //             comedyBook = books.filter(el => el.categories == 'comedy')
    //             setComedy(comedyBook)
    //             let sportBook = []
    //             sportBook = books.filter(el => el.categories == 'sport')
    //             setSport(sportBook)
    //             let actionBook = []
    //             actionBook = books.filter(el => el.categories == 'action')
    //             setAction(actionBook)
    //         })
    // }, [])

//option 2
    useEffect(() => {
        let comedyBook = []
        let sportBook = []
        let actionBook = []
        console.log('ssss')

        axios.get('http://127.0.0.1:3000/books')
            .then(res => {
                setBooks(res.data.data.books)
            }).then(() => {
                comedyBook = books.filter(el => el.categories == 'comedy')
                sportBook = books.filter(el => el.categories == 'sport')
                actionBook = books.filter(el => el.categories == 'action')
            }).then(() => {
                setComedy(comedyBook)
                setSport(sportBook)
                setAction(actionBook)
            })
    }, [])



    return (
        <div className="home-container">
            <p className="title-cat">Comedy Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {comedyBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>

            <p className="title-cat">Sport Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {sportBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>

            <p className="title-cat">Action Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {actionBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>
        </div>
    )
}

export default HomePage

问题根源与解决方案

1. 无限循环的原因

当useEffect不添加依赖数组时,组件每次渲染(包括setState触发的重渲染)都会重新执行useEffect内部代码。每次执行都会调用setBooks等setState方法,触发组件重渲染,进而再次执行useEffect,形成无限循环。

2. 刷新后页面为空的核心问题

两种写法都犯了同一个错误:在setBooks之后直接使用books state进行筛选。setState是异步操作,调用setBooks后,books并不会立即更新,此时筛选的还是初始的空数组[],所以分类后的state都是空数组,页面自然没有内容。

另外,刷新页面后useEffect其实是生效的(可以看console.log('ssss')是否打印),只是因为上述逻辑错误,导致分类state没有被正确赋值。

3. 正确写法

不需要单独维护分类后的state,直接基于books进行实时筛选即可,既减少state冗余,也避免异步更新的问题:

import React, { useEffect, useState } from "react";
import axios from "axios"
import { useNavigate } from "react-router-dom";
import BookItem from "../bookItem/bookItem";
import './Home.css'

function HomePage() {
    const [books, setBooks] = useState([])
    let navigate = useNavigate();

    useEffect(() => {
        axios.get('http://127.0.0.1:3000/books')
            .then(res => {
                setBooks(res.data.data.books)
            })
    }, [])

    // 实时筛选分类书籍
    const comedyBooks = books.filter(el => el.categories === 'comedy')
    const sportBooks = books.filter(el => el.categories === 'sport')
    const actionBooks = books.filter(el => el.categories === 'action')

    return (
        <div className="home-container">
            <p className="title-cat">Comedy Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {comedyBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>

            <p className="title-cat">Sport Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {sportBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>

            <p className="title-cat">Action Books</p>
            <div className="line-bottom"></div>
            <div className="books">
                {actionBooks.map(item => {
                    return <BookItem key={item._id} item={item} />
                })}
            </div>
        </div>
    )
}

export default HomePage

4. 疑问解答

  • 在useEffect中使用setState是否有问题?
    完全没问题,这是React开发中很常见的场景,比如从接口获取数据后更新state。只要注意依赖数组的正确设置,以及setState的异步特性即可。
  • 为什么刷新页面后useEffect不生效?
    刷新后useEffect是生效的,只是你之前的代码中,在setBooks后立即使用books进行筛选,而setState是异步的,此时books还是初始空数组,导致分类结果为空,看起来像useEffect没生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:20:25