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

Next.js组件同时使用async/await与useState的冲突问题求助

问题解决步骤

1. 修复客户端组件的标记与async/await报错

你对async/await的理解有误:客户端组件完全可以使用async/await编写异步函数,报错的根源不是handleSubmit里的async,而是以下可能:

  • 'use client'指令没有放在组件文件的最顶部
  • 误将组件本身声明为async函数(你的代码里没有,但需确认)

正确做法:在包含AddUserForm的文件最顶部添加'use client',确保它是文件的第一行(注释需放在它后面):

'use client'; // 必须放在文件最顶部

import { useState } from 'react';
import { useMutation, gql } from '@apollo/client';

const ADD_USER = gql`
  mutation AddUser($input: AddUserInput!) {
    addUser(input: $input) {
      id
      name 
      email
    }
  } 
`;

const AddUserForm: React.FC = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const [addUser] = useMutation(ADD_USER);

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    try {
      await addUser({
        variables: {
          input: {
            name,
            email,
          },
        },
      });

      // 此处不能直接更新本地JSON文件,看下方说明
    } catch (error) {
      console.error('Error adding user:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      </label>
      <label>
        Email:
        <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
      </label>
      <button type="submit">Add User</button>
    </form>
  );
};

const AddUser: NextPage = () => {
  return (
    <div>
      <h1>Add User</h1>
      <AddUserForm />
    </div>
  );
};

export default AddUser;

2. 解决本地JSON文件更新的问题

浏览器环境没有读写服务器/本地文件系统的权限,不能在客户端组件里直接修改本地JSON文件。要实现这个功能,需要:

  • 创建一个Next.js API路由(根据你用的是App Router还是Pages Router,选择对应路径)
  • 在API路由里完成读取、修改、写入JSON文件的操作
  • 在客户端的handleSubmit里调用这个API,替代直接操作文件

示例API路由(App Router)

创建app/api/add-user/route.ts:

import fs from 'fs/promises';
import path from 'path';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const { name, email } = await request.json();
    // 构建JSON文件路径
    const jsonFilePath = path.join(process.cwd(), 'data', 'users.json');
    
    // 读取现有数据
    const data = await fs.readFile(jsonFilePath, 'utf-8');
    const users = JSON.parse(data);
    
    // 添加新用户
    const newUser = { id: Date.now().toString(), name, email };
    users.push(newUser);
    
    // 写回文件
    await fs.writeFile(jsonFilePath, JSON.stringify(users, null, 2));
    
    return NextResponse.json({ success: true, user: newUser });
  } catch (error) {
    return NextResponse.json({ success: false, error: 'Failed to add user' }, { status: 500 });
  }
}

修改客户端组件的handleSubmit

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();

  try {
    // 先调用GraphQL mutation(如果需要)
    await addUser({
      variables: {
        input: {
          name,
          email,
        },
      },
    });

    // 再调用API更新本地JSON文件
    const response = await fetch('/api/add-user', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ name, email }),
    });

    if (!response.ok) throw new Error('Failed to update JSON file');
    const result = await response.json();
    console.log('User added to JSON:', result.user);

    // 清空表单
    setName('');
    setEmail('');
  } catch (error) {
    console.error('Error adding user:', error);
  }
};

3. 关键注意事项

  • 客户端组件可以自由使用async/await编写异步回调函数,只有组件本身被声明为async函数时才会报错(React不支持异步组件,除非配合Suspense使用)
  • 本地文件操作必须在服务端执行,客户端没有权限直接读写文件
  • 如果使用App Router,page.tsx默认是服务端组件,引用客户端组件时只需确保客户端组件有'use client'标记即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 19:47:49