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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:01:17