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

Next.js 13 Beta组件报错求助:use client与Promise渲染冲突

问题解决:Next.js 13 Beta中Client Component的async声明错误

错误原因

  • 添加"use client"后报错:因为你把组件声明成了async函数(export default async function Student())。React无法直接渲染Promise对象,而async组件会返回Promise,因此触发Objects are not valid as a React child错误。
  • 移除"use client"后报错:组件使用了useState、useRouter这类客户端专属API,必须标记为Client Component才能运行。

解决方案

去掉组件的async修饰符——Client Component本身不能是async的。异步逻辑可以放在组件内部的函数中(比如你的handleSubmit已经是async的,这完全没问题)。

修正后的代码

"use client";

import { useRouter } from "next/navigation"
import { useState } from "react"

async function addNewStudent(sInfo, refresh){
    await fetch('/api/students', {
        method: "POST",
        body: JSON.stringify(sInfo),
        headers: {
            'Content-Type': 'application/json' // 补充请求头,确保后端正确解析JSON
        }
    });

    refresh()
}

// 移除async修饰符
export default function Student() {

    const router = useRouter()
    const [sInfo, setSInfo] = useState({
        sName:"",
        sSurname:"",
        sMobile:"",
        sEmail:"",
        sAddress:"",
        sClass:""
    })

    const handleChange = (event) => {
        setSInfo({ ...sInfo, [event.target.name]: event.target.value });
         
      };
    
    const handleSubmit = async (e) => {
        e.preventDefault()
        await addNewStudent(sInfo, router.refresh)
    }

  return (
    <form onSubmit={handleSubmit} className="relative bg-white rounded-lg shadow dark:bg-gray-700">
                
                <div className="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600">
                    <h3 className="text-xl font-semibold text-gray-900 dark:text-white">
                        Edit Student
                    </h3>
                    <button type="button" className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide="editUserModal">
                        <svg aria-hidden="true" className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>  
                    </button>
                </div>
                
                <div className="p-6 space-y-6">
                    <div className="grid grid-cols-12 gap-6">
                        <div className="col-span-12 sm:col-span-4">
                            <label htmlFor="first-name" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Name</label>
                            <input type="text" value={sInfo.sName} onChange={handleChange} name="sName" id="first-name" className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="student name" />
                        </div>
                        <div className="col-span-12 sm:col-span-4">
                            <label htmlFor="last-name" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Lastname</label>
                            <input type="text" value={sInfo.sSurname} onChange={handleChange} name="sSurname" id="last-name" className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="student lastname" />
                        </div>
                        <div className="col-span-12 sm:col-span-4">
                            <label htmlFor="email" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Email</label>
                            <input type="email" value={sInfo.sEmail} onChange={handleChange} name="sEmail" id="email" className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="email" />
                        </div>
                        <div className="col-span-12 sm:col-span-4">
                            <label htmlFor="phone-number" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Mobile</label>
                            <input type="number" value={sInfo.sMobile} onChange={handleChange} name="sMobile" id="phone-number" className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="mobile" />
                        </div>
                        <div className="col-span-12 sm:col-span-4">
                        <label htmlFor="class"  className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Class</label>
<select id="class" value={sInfo.sClass} onChange={handleChange} name="sClass" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
  <option selected>Class</option>
  <option value="5">5. Sınıf</option>
  <option value="6">6. Sınıf</option>
  <option value="7">7. Sınıf</option>
  <option value="8">8. Sınıf</option>
  <option value="9">9. Sınıf</option>
  <option value="10">10. Sınıf</option>
  <option value="11">11. Sınıf</option>
  <option value="12">12. Sınıf</option>
</select>
                        </div>
                        
                        <div className="col-span-12 sm:col-span-4">
                            <label htmlFor="department" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Address</label>
                            <input type="text" value={sInfo.sAddress} onChange={handleChange} name="sAddress" id="department" className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="address" />
                        </div>
                        
                    </div>
                </div>
               
                <div className="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600">
                    <button type="submit" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save all</button>
                </div>
            </form>
  )
}

额外提示

  • 在fetch请求中补充Content-Type: application/json请求头,避免后端无法解析JSON数据。
  • Client Component内部可以包含异步函数,但组件本身不能是async的——只有Server Component支持在组件顶层直接用async/await获取数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:00:57