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

NextJS13客户端组件输入时反复触发loading.jsx加载问题求助

问题原因与解决方案

核心问题:客户端组件被错误定义为异步函数

在Next.js 13的App Router中,标记了'use client'的客户端组件不能是异步(async)函数。你把Books组件写成了async () => {},这会让Next.js误判它为需要加载服务器数据的组件——每次组件因状态变化(比如输入框onChange修改query)重新渲染时,都会触发路由级别的loading.jsx,因为框架认为这个"异步组件"正在加载服务器数据。

修复步骤

  1. 移除组件的async关键字:客户端组件必须是普通同步函数。
  2. 修正loading状态逻辑:初始状态设为true,确保数据加载完成前显示自定义loading(如果需要)。

修正后的Books组件代码

'use client';
import { useState, useEffect } from "react";
import Link from "next/link";
import LoadingPage from "../loading";

async function getBooks() {
    const res = await fetch("http://localhost:3000/api/books");
    const json = await res.json();
    return json;
}

// 移除async关键字,改为普通函数
const Books = () => {
    const [books, setBooks] = useState([]);
    // 初始loading设为true,确保数据加载时显示状态
    const [loading, setLoading] = useState(true);
    const [query, setQuery] = useState("");

    useEffect(() => {
        getBooks().then((books) => {
            setBooks(books);
            setLoading(false);
        }).catch(() => {
            setLoading(false);
        });
    },[]);

    // 可以根据loading状态显示自定义loading组件,而非路由级的loading.jsx
    if(loading){ 
        return <LoadingPage />
    }

    const handleSubmit = async (e) => {
        e.preventDefault();
        console.log(query);
        // 后续搜索逻辑可以在这里补充
    }

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type="text" placeholder="Search Books..." value={query} onChange={(e) => setQuery(e.target.value)} className="input input-bordered w-full max-w-xs" />
                <button type="submit" className="btn btn-primary">Search</button>
            </form>
            {books.map((book) => (
                <div key={book.id}>
                    <div className="card w-96 bg-base-100 shadow-xl">
                        <figure>
                            <img src={book.img} width="200" height="150" alt={book.title} />
                        </figure>
                        <div className="card-body">
                            <h2 className="card-title">{book.id}</h2>
                            <p>{book.title}</p>
                            <div className="card-actions justify-end">
                                <Link href={book.link} className="btn btn-primary">See in Amazon</Link>
                            </div>
                        </div>                    
                    </div> 
                    <br />
                </div>              
            ))}           
        </div>
    )
}

export default Books;

补充说明

  • App Router中的loading.jsx是路由段级别的加载组件,仅在路由导航、服务器组件加载数据时触发,客户端组件的本地状态变化(比如输入框输入)本不该触发它。
  • 客户端组件内的异步逻辑(比如数据获取)必须放在useEffect或其他客户端生命周期钩子中,不能直接把组件定义为async函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 07:57:16