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

Next.js+Laravel Sanctum项目API重复请求问题求助

解决Next.js客户端组件重复发送API请求的问题

问题原因

你直接在组件函数顶层调用了fetchPost(),组件每次渲染时都会执行这个函数,而setPost、setTitle等状态更新操作又会触发组件重新渲染,形成无限渲染循环,导致API请求被重复发送。

解决方法

使用React的useEffect钩子包裹数据获取逻辑,控制请求仅在组件挂载或指定依赖项变化时执行:

  1. 导入useEffect
  2. 将fetchPost()放入useEffect中,设置依赖项为params.id(仅当post ID变化时重新请求)
  3. 合并重复的usePosts调用,避免多次初始化hook

修改后的完整代码

'use client'

import { usePosts } from "@/hooks/post"
import { useState, useEffect } from "react" // 新增useEffect导入
import InputError from "@/components/InputError";
import styles from "../page.module.css";

const PostEditForm = ({params}) => {

    // 合并usePosts的解构,避免重复调用
    const { getPost, updatePost } = usePosts();

    const [post, setPost] = useState(null);
    const [title, setTitle] = useState('')
    const [body, setBody] = useState('')
    const [errors, setErrors] = useState([])
    const [isLoading, setIsLoading] = useState(true) // 可选:添加加载状态
    const [fetchError, setFetchError] = useState(null) // 可选:添加错误状态

   const fetchPost = async () => {
        setIsLoading(true)
        setFetchError(null)
        try{
            const postData = await getPost(params.id)
            setPost(postData)
            setTitle(postData.title)
            setBody(postData.body)
        }catch(error){
            setFetchError(error.message || '获取文章失败')
            console.error('获取文章出错:', error)
        } finally {
            setIsLoading(false)
        }
   }

    // 使用useEffect包裹,仅在params.id变化时执行
    useEffect(() => {
        fetchPost()
    }, [params.id, getPost]) // 依赖项包含params.id和getPost,避免闭包问题

    const submitForm = async event => {
        event.preventDefault()
        await updatePost(params.id,{
            title,
            body,
            setErrors
        })
    }

    // 可选:根据加载状态渲染不同内容
    if(isLoading) return <div className={styles.loading}>加载中...</div>
    if(fetchError) return <div className={styles.error}>{fetchError}</div>
    if(!post) return <div className={styles.error}>文章不存在</div>

    return (
        <form onSubmit={submitForm} className={styles.form}>
            <div>
                <label>标题</label>
                <input 
                    type="text" 
                    value={title} 
                    onChange={(e) => setTitle(e.target.value)}
                />
                {errors.title && <InputError message={errors.title} />}
            </div>
            <div>
                <label>内容</label>
                <textarea 
                    value={body} 
                    onChange={(e) => setBody(e.target.value)}
                />
                {errors.body && <InputError message={errors.body} />}
            </div>
            <button type="submit">更新文章</button>
        </form>
    )
}

export default PostEditForm

额外说明

  • 依赖项数组[params.id, getPost]:确保当文章ID变化时重新请求,同时如果getPost函数有变化(比如hook内部逻辑更新)也会重新执行,避免闭包问题。
  • 添加加载和错误状态:提升用户体验,避免页面出现异常内容。
  • 错误处理:不再忽略catch块,方便排查问题和给用户反馈。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:52:55