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

NextJS报错:无法直接向客户端组件传递函数的解决方案求助

解决Next.js中Server组件函数传递给Client组件的报错问题

错误原因

Next.js 13+ App Router里,Server组件的函数不能直接传递给标记了'use client'的Client组件——两者运行环境不同,Server组件函数在服务器端执行,Client组件在浏览器端执行,必须显式标记函数为Server Action,或换用前端直接调用API的方式。


解决方案1:使用Server Actions(推荐)

Server Action允许在Client组件中安全调用服务器端函数,不会暴露后端API地址。

步骤1:修改updatePassword.js,标记为Server Action

在函数顶部添加'use server'指令,同时修正API传参(原代码中{formData}会导致后端接收嵌套对象,直接传formData即可):

'use server';

import api from '@/services/AxiosSetup';

export default async function updatePassword(formData) {
    try {
        const response = await api.post('/auth/change-password', formData);
        if (response.data) {
            return response.data;
        }
    } catch (error) {
        console.error(error.message);
        throw error;
    }
}

步骤2:修改Client组件PasswordForm.js,直接导入Server Action

无需通过Server组件传递函数,直接在Client组件中导入并调用:

'use client';

import React, { useState } from "react";
import updatePassword from '@/app/api/updatePassword';
import { Loader } from 'rsuite';
import "rsuite/dist/rsuite.min.css";

const PasswordForm = () => {
    const [buttonText, setButtonText] = useState('Wachtwoord bijwerken');
    const [formData, setFormData] = useState({
        currentPassword: '',
        password: '',
        passwordConfirmation: ''
    });
    const [isLoading, setIsLoading] = useState(false);

    const handleInputChange = (name, value) => {
        setFormData(prev => ({ ...prev, [name]: value }));
    };

    const handlePassword = async (event) => {
        event.preventDefault();
        setIsLoading(true);
        setButtonText('Bezig met bijwerken...');
        
        try {
            await updatePassword(formData);
            // 成功后重置表单
            setFormData({ currentPassword: '', password: '', passwordConfirmation: '' });
        } catch (error) {
            console.error('Error updating password:', error);
        } finally {
            setButtonText('Wachtwoord bijwerken');
            setIsLoading(false);
        }
    };

    return (
        <div id="change-password">
            <form onSubmit={handlePassword}>
                <div className="w-full mb-3 form-field">
                    <input 
                        type="password" 
                        placeholder="Huidig wachtwoord" 
                        value={formData.currentPassword} 
                        onChange={(e) => handleInputChange('currentPassword', e.target.value)}
                        className="block w-full rounded p-1.5 border border-gray-300 text-gray-900"
                        disabled={isLoading} 
                        required 
                    />
                </div>
                <div className="w-full mb-3 form-field">
                    <input 
                        type="password" 
                        placeholder="Nieuw wachtwoord" 
                        value={formData.password} 
                        onChange={(e) => handleInputChange('password', e.target.value)}
                        className="block w-full rounded p-1.5 border border-gray-300 text-gray-900"
                        disabled={isLoading} 
                        required 
                    />
                </div>
                <div className="w-full mb-3 form-field">
                    <input 
                        type="password" 
                        placeholder="Bevestig nieuw wachtwoord" 
                        value={formData.passwordConfirmation} 
                        onChange={(e) => handleInputChange('passwordConfirmation', e.target.value)}
                        className="block w-full rounded p-1.5 border border-gray-300 text-gray-900"
                        disabled={isLoading} 
                        required 
                    />
                </div>
                <div className="form-footer">
                    <input type="submit" value={buttonText} className="w-full font-medium p-3 mt-3 rounded button" disabled={isLoading} />
                    {isLoading ? <Loader size="sm" className="loader" /> : null}
                </div>
            </form>
        </div>
    );
};

export default PasswordForm;

步骤3:修改Server组件Instellingen/page.js,移除函数传递

不再需要传递updatePassword props:

import Header from '../components/header/Header';
import PasswordForm from '../components/password-form/PasswordForm';

export default function Instellingen() {
  return (
    <>
      <Header />
      <main className="main-content h-screen bg-slate-50">
        <div className="container mx-auto flex justify-between items-center px-5">
          <div className="page-content">
            <h1 className="text-3xl mb-8">Instellingen</h1>
            <div className="block p-8 bg-white border border-slate-200">
              <h2 className="text-xl mb-4">Wachtwoord wijzigen</h2>
              <PasswordForm />
            </div>
          </div>
        </div>
      </main>
    </>
  )
}

解决方案2:Client组件直接调用API

如果不需要Server Action的服务器端执行优势,可以直接在Client组件中调用后端API:

修改PasswordForm.js,直接使用Axios调用API

'use client';

import React, { useState } from "react";
import api from '@/services/AxiosSetup';
import { Loader } from 'rsuite';
import "rsuite/dist/rsuite.min.css";

const PasswordForm = () => {
    const [buttonText, setButtonText] = useState('Wachtwoord bijwerken');
    const [formData, setFormData] = useState({
        currentPassword: '',
        password: '',
        passwordConfirmation: ''
    });
    const [isLoading, setIsLoading] = useState(false);

    const handleInputChange = (name, value) => {
        setFormData(prev => ({ ...prev, [name]: value }));
    };

    const handlePassword = async (event) => {
        event.preventDefault();
        setIsLoading(true);
        setButtonText('Bezig met bijwerken...');
        
        try {
            const response = await api.post('/auth/change-password', formData);
            if (response.data) {
                setFormData({ currentPassword: '', password: '', passwordConfirmation: '' });
            }
        } catch (error) {
            console.error('Error updating password:', error);
        } finally {
            setButtonText('Wachtwoord bijwerken');
            setIsLoading(false);
        }
    };

    return (
        {/* 渲染代码与解决方案1一致 */}
    );
};

export default PasswordForm;

此时Instellingen/page.js同样不需要传递函数,保持解决方案1中的修改即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 22:38:10