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

Next.js中useEffect触发两次GET请求,原因是什么?

解决React组件中API GET请求重复触发的问题

重复请求的核心原因

最常见的触发原因是React开发环境的严格模式(Strict Mode),它会刻意重复执行useEffect、组件初始化等逻辑,用来检测潜在的副作用问题。这种重复仅在开发环境存在,生产环境不会出现,但考虑到你的API会触发Active Directory操作,必须确保副作用逻辑是幂等的,或者添加防护机制避免重复执行。

具体修复步骤

1. 添加请求防护标志

在useEffect中加入挂载状态标志,防止重复执行请求逻辑,同时避免组件卸载后更新状态:

function Ad() {
    const [data, setData] = useState(null)
    const [isLoading, setLoading] = useState(false)
    const [isRemoved, setIsRemoved] = useState(null) // 用状态管理移除状态,替代直接DOM操作

    useEffect(() => {
        let isMounted = true
        // 仅在未获取数据时发起请求
        if (isMounted && !data) {
            setLoading(true)
            fetch('../api/decom/ad')
                .then(response => response.json())
                .then(fetchedData => {
                    if (isMounted) {
                        setData(fetchedData)
                        setLoading(false)
                        if (fetchedData.exists) {
                            handleRemove()
                        }
                    }
                })
                .catch(error => {
                    if (isMounted) setLoading(false)
                })
        }
        // 组件卸载时重置标志
        return () => { isMounted = false }
    }, [data])

    const handleRemove = () => {
        fetch("../api/decom/ad", { method: "DELETE" })
            .then(response => response.json())
            .then(removeData => setIsRemoved(removeData.removed))
            .catch(error => { /* 处理删除请求错误 */ })
    }

    // 用状态控制渲染,替代DOM操作
    if (data?.exists) {
        return (
            <a className={styles.card}>
                <h2>AD</h2>
                <p>Exists: { greenCircle } </p>
                <div className={styles.parent}>
                    <p className={styles.child}>Removed:</p>
                    {isRemoved === null ? (
                        <div><div className={styles.loader}><div></div><div></div><div></div></div></div>
                    ) : (
                        <p>Removed: {isRemoved ? greenCircle : redCircle}</p>
                    )}
                </div>
            </a>
        )
    }

    if (data?.exists === false) {
        return (
            <a className={styles.card}>
                <h2>AD</h2>
                <p>Exists: {redCircle} </p>
                <p>Removed:{redCircle}</p>
            </a>
        )
    }

    if (isLoading) {
        return (
            <a className={styles.card}>
                <h2>AD</h2>
                <div className={styles.parent}>
                    <p className={styles.child}>Exists:</p>
                    <div><div className={styles.loader}><div></div><div></div><div></div></div></div>
                </div>
                <p>Removed:{redCircle}</p>
            </a>
        )
    }

    return null
}

2. 替换DOM操作为React状态管理

原代码中直接操作DOM的方式不符合React的状态管理逻辑,改用isRemoved状态控制移除状态的渲染,避免DOM操作引发的冲突。

3. 后端幂等性保障

如果你的API不是幂等的(比如重复执行DELETE会多次删除AD对象),必须在后端添加校验逻辑,比如通过资源状态或请求ID判断,避免重复操作带来的风险。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:54:35