Remix聊天应用:提交表单时本地存储消息至聊天历史的实现方法
在Remix中提交表单时本地保存聊天消息的方案
下面提供两种不破坏Remix原有工作流程的实现方式,帮你在提交消息时本地保存聊天历史:
方案一:利用Fetcher表单的onSubmit事件获取值
无需将输入框改为受控组件,直接在表单提交时读取输入值并添加到本地历史,同时保留Remix默认的表单提交流程:
import { useFetcher, useState } from "@remix-run/react"; export default function Chat() { const fetcher = useFetcher(); // 本地存储聊天历史,区分用户消息和机器人消息 const [chatHistory, setChatHistory] = useState<{type: 'user' | 'bot', content: string}[]>([]); const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { // 从表单中获取输入框的值 const inputElement = e.currentTarget.chatMessage as HTMLInputElement; const message = inputElement.value.trim(); if (message) { // 将用户消息添加到本地历史 setChatHistory(prev => [...prev, { type: 'user', content: message }]); // 清空输入框(可选) inputElement.value = ''; } // 不阻止默认行为,让Remix的fetcher正常提交到后端 }; return ( <div> {/* 渲染聊天历史 */} <div className="chat-history"> {chatHistory.map((msg, idx) => ( <div key={idx} className={`message ${msg.type}`}> {msg.content} </div> ))} {/* 显示后端处理中的加载状态 */} {fetcher.state === 'loading' && <div className="message bot">正在回复...</div>} </div> <fetcher.Form method="post" onSubmit={handleSubmit}> <input type="text" name="chatMessage" placeholder="输入消息..." /> <button type="submit" disabled={fetcher.state === 'loading'}> 发送 </button> </fetcher.Form> </div> ); }
方案二:受控组件管理输入值
通过useState绑定输入框,直接使用状态值添加到本地历史,再手动触发fetcher提交,适合需要对输入做实时处理的场景:
import { useFetcher, useState } from "@remix-run/react"; export default function Chat() { const fetcher = useFetcher(); const [chatHistory, setChatHistory] = useState<{type: 'user' | 'bot', content: string}[]>([]); // 受控输入框的状态 const [inputValue, setInputValue] = useState(''); const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); // 阻止默认表单提交,改为手动触发fetcher const message = inputValue.trim(); if (!message) return; // 添加用户消息到本地历史 setChatHistory(prev => [...prev, { type: 'user', content: message }]); // 清空输入框 setInputValue(''); // 手动调用fetcher提交数据到后端 fetcher.submit( { chatMessage: message }, { method: 'post' } ); }; return ( <div> <div className="chat-history"> {chatHistory.map((msg, idx) => ( <div key={idx} className={`message ${msg.type}`}> {msg.content} </div> ))} {fetcher.state === 'loading' && <div className="message bot">正在回复...</div>} </div> <form onSubmit={handleSubmit}> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} placeholder="输入消息..." /> <button type="submit" disabled={fetcher.state === 'loading'}> 发送 </button> </form> </div> ); }
补充:获取后端回复并更新历史
如果后端action返回机器人回复,可以监听fetcher.data的变化,将回复添加到本地历史:
后端Action修改:
export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const chatMessage = formData.get("chatMessage") as string; // 生成机器人回复(你的原有逻辑) const botReply = await generateChatReply(chatMessage); // 返回回复内容给前端 return { botReply }; }
客户端添加监听:
import { useEffect } from 'react'; // 在Chat组件中添加 useEffect(() => { if (fetcher.data?.botReply) { // 将机器人回复添加到历史 setChatHistory(prev => [...prev, { type: 'bot', content: fetcher.data.botReply }]); // 清空fetcher.data避免重复添加 fetcher.load('/your-chat-route-path'); // 替换为你的聊天页面路由 } }, [fetcher.data, setChatHistory, fetcher]);
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

