MERN博客中MainPage的loading判断引发useEffect无限触发,求原因
问题:MainPage的loading判断为何导致Pagination组件useEffect无限循环?
我在学习MERN栈开发博客,给博客加了带筛选的分页功能。原本父组件里的dispatch逻辑太多,就移到了Pagination组件里,用动态import导入AsyncThunk函数并dispatch。现在功能能正常获取数据,但出现useEffect持续触发dispatch的无限循环问题。后来发现注释掉MainPage里的loading判断后,循环就停止了,想知道为什么。
相关代码片段
父组件MainPage代码
export const MainPage = () => { const { loading, popularPosts } = useSelector(state => state.post) if (loading) { return ( <div className="text-xl text-center text-white py-10"> Loading... </div> ) } return ( <div className='max-w-[900px] mx-auto py-10'> <div className="flex justify-between gap-8"> <Pagination request={'getAllPosts'} /> <div className="basis-1/5"> <div className='text-xs uppercase text-white'> POPULAR: </div> { popularPosts?.map((post, index) => ( <PopularPosts key={index} post={post} /> )) } </div> </div> </div> ) }
分页组件Pagination代码
export function Pagination({ request }) { const location = useLocation() const dispatch = useDispatch() const path = location.pathname const { postsNum, loading, posts, page } = useSelector(state => state.post) console.log(postsNum, loading, posts, page) const currentPage = (new URLSearchParams(location.search).get('page')) === page ? page : (new URLSearchParams(location.search).get('page')) let filter = (new URLSearchParams(location.search).get('filter')) === null ? '' : (new URLSearchParams(location.search).get('filter')) console.log(currentPage, filter) useEffect(() => { console.log('message') import('../../redux/fetures/post/postSlice').then((res) => { dispatch(res[request]({currentPage, filter})) }).catch((err) => { console.log(err) }) }, [dispatch, currentPage, filter, request]) filter = filter === '' ? '-createdAt' : filter // 剩余组件代码... }
AsyncThunk函数getAllPosts代码
export const getAllPosts = createAsyncThunk('post/getAllPosts', async ({ currentPage, filter }) => { try { let dataRes = [] filter = filter[0] ? filter.replace(/\+/g, '%2B') : filter filter = filter ? '&filter=' + filter : '' if (currentPage && currentPage !== 'null') { const { data } = await Axios.get(`/posts/?page=${currentPage}${filter}`) dataRes = data } else { const { data } = await Axios.get(`/posts/?${filter.slice(1)}`) dataRes = data } console.log(dataRes) return dataRes } catch (err) { console.log(err) } })
Reducer中处理getAllPosts的逻辑
// GET ALL POSTS [getAllPosts.pending]: (state, action) => { state.loading = true state.status = null }, [getAllPosts.fulfilled]: (state, action) => { state.loading = false state.posts = action.payload?.responsePosts state.postsNum = action.payload?.postsNum state.popularPosts = action.payload?.popularPosts }, [getAllPosts.rejected]: (state, action) => { state.loading = false },
问题原因分析
核心原因是组件挂载-卸载的循环触发,完整流程如下:
- 初始渲染时,若Redux中
loading为false,MainPage会渲染Pagination组件。 - Pagination挂载后,其useEffect触发,dispatch
getAllPosts请求。此时Redux reducer进入pending状态,将loading设为true。 - Redux状态更新触发MainPage重新渲染,此时
loading为true,MainPage会卸载Pagination,返回Loading组件。 - 当
getAllPosts请求完成,reducer进入fulfilled状态,将loading设为false。 - Redux状态再次更新,MainPage重新渲染,
loading为false,于是重新挂载Pagination组件。 - Pagination重新挂载后,其useEffect会再次触发(组件挂载时useEffect会执行一次),dispatch请求,重复上述流程,形成无限循环。
当你注释掉MainPage的loading判断后,Pagination组件会始终保持挂载状态:请求完成后Redux状态更新,Pagination的useEffect依赖项(currentPage、filter等)如果没有变化,就不会再次触发dispatch,循环自然终止。
另外补充:你的Pagination组件中currentPage的计算逻辑依赖Redux的page状态,但当前reducer的fulfilled分支并没有更新state.page,这可能导致currentPage在每次渲染时都可能生成新的引用(比如URL参数和Redux的page不一致时),进一步加剧循环风险,但核心触发点还是组件的挂载卸载循环。
内容的提问来源于stack exchange,提问作者Dmytro
相关产品推荐
相关产品推荐

