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

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
},

问题原因分析

核心原因是组件挂载-卸载的循环触发,完整流程如下:

  1. 初始渲染时,若Redux中loading为false,MainPage会渲染Pagination组件。
  2. Pagination挂载后,其useEffect触发,dispatchgetAllPosts请求。此时Redux reducer进入pending状态,将loading设为true。
  3. Redux状态更新触发MainPage重新渲染,此时loading为true,MainPage会卸载Pagination,返回Loading组件。
  4. 当getAllPosts请求完成,reducer进入fulfilled状态,将loading设为false。
  5. Redux状态再次更新,MainPage重新渲染,loading为false,于是重新挂载Pagination组件。
  6. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:58:10