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
相关产品推荐
相关产品推荐

