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
相关产品推荐
相关产品推荐

