使用 React 实现 AI 对话窗口的核心逻辑,主要围绕对话状态管理用户输入交互AI 响应模拟/对接UI 渲染四个部分展开。以下是具体实现思路和代码示例:

一、核心逻辑拆解

  1. 对话数据结构设计
    用数组存储对话记录,每条消息包含 角色(用户/AI)、内容状态(加载中/完成)等信息。

  2. 用户输入交互

    • 输入框获取用户输入,回车或点击发送按钮提交。
    • 提交后清空输入框,并立即将用户消息添加到对话记录。
  3. AI 响应处理

    • 模拟 AI 思考过程(显示“正在输入…”)。
    • 实际场景中对接 AI 接口(如 OpenAI API),获取响应后更新对话记录。
  4. UI 渲染与滚动

    • 动态渲染对话列表,区分用户和 AI 的消息样式。
    • 新消息发送后自动滚动到最新位置。

二、代码实现示例

import { useState, useRef, useEffect } from 'react';

const AIChatWindow = () => {
  // 对话记录:[{ role: 'user' | 'ai', content: string, loading: boolean }]
  const [messages, setMessages] = useState([
    { role: 'ai', content: '你好!有什么可以帮你的吗?', loading: false }
  ]);
  const [input, setInput] = useState('');
  const chatEndRef = useRef(null); // 用于自动滚动到最新消息

  // 自动滚动到最新消息
  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  // 模拟AI响应(实际项目中替换为接口请求)
  const getAIResponse = (userInput) => {
    // 简单模拟不同问题的回答
    const replies = {
      '你好': '你好呀!😊',
      '什么是React': 'React是一个用于构建用户界面的JavaScript库...',
      '默认回复': '我正在学习中,这个问题我还不太清楚呢~'
    };
    return replies[userInput] || replies['默认回复'];
  };

  // 发送消息
  const handleSend = async () => {
    if (!input.trim()) return; // 空消息不发送

    // 1. 添加用户消息到对话
    const userMessage = { role: 'user', content: input, loading: false };
    setMessages(prev => [...prev, userMessage]);
    setInput(''); // 清空输入框

    // 2. 添加AI"正在输入"状态
    setMessages(prev => [...prev, { role: 'ai', content: '', loading: true }]);

    // 3. 模拟AI思考延迟(实际项目中这里调用API)
    setTimeout(() => {
      const aiResponse = getAIResponse(input.trim());
      // 更新AI消息(替换"正在输入"状态)
      setMessages(prev => {
        const newMessages = [...prev];
        newMessages.pop(); // 移除"正在输入"
        newMessages.push({ role: 'ai', content: aiResponse, loading: false });
        return newMessages;
      });
    }, 1000); // 模拟1秒思考时间
  };

  return (
    <div style={styles.container}>
      <div style={styles.chatBox}>
        {/* 对话列表 */}
        {messages.map((msg, index) => (
          <div 
            key={index} 
            style={msg.role === 'user' ? styles.userMsg : styles.aiMsg}
          >
            <span style={styles.roleLabel}>
              {msg.role === 'user' ? '你' : 'AI'}
            </span>
            <div style={styles.content}>
              {msg.loading ? '正在输入...' : msg.content}
            </div>
          </div>
        ))}
        {/* 用于自动滚动的锚点 */}
        <div ref={chatEndRef} />
      </div>

      {/* 输入区域 */}
      <div style={styles.inputArea}>
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && handleSend()}
          placeholder="输入消息..."
          style={styles.input}
        />
        <button onClick={handleSend} style={styles.sendBtn}>
          发送
        </button>
      </div>
    </div>
  );
};

// 样式定义
const styles = {
  container: {
    width: 400,
    height: 600,
    border: '1px solid #ddd',
    borderRadius: 8,
    display: 'flex',
    flexDirection: 'column',
    margin: '20px auto'
  },
  chatBox: {
    flex: 1,
    padding: 16,
    overflowY: 'auto',
    backgroundColor: '#f9f9f9'
  },
  userMsg: {
    textAlign: 'right',
    marginBottom: 12
  },
  aiMsg: {
    textAlign: 'left',
    marginBottom: 12
  },
  roleLabel: {
    fontSize: 12,
    color: '#666',
    marginBottom: 4,
    display: 'inline-block'
  },
  content: {
    maxWidth: '70%',
    padding: 10,
    borderRadius: 12,
    display: 'inline-block'
  },
  userMsg: {
    textAlign: 'right'
  },
  userMsg: {
    '& $content': {
      backgroundColor: '#0078d7',
      color: 'white'
    }
  },
  aiMsg: {
    '& $content': {
      backgroundColor: 'white',
      border: '1px solid #ddd'
    }
  },
  inputArea: {
    display: 'flex',
    padding: 12,
    borderTop: '1px solid #ddd'
  },
  input: {
    flex: 1,
    padding: 8,
    borderRadius: 4,
    border: '1px solid #ddd',
    outline: 'none'
  },
  sendBtn: {
    marginLeft: 8,
    padding: 8 16,
    backgroundColor: '#0078d7',
    color: 'white',
    border: 'none',
    borderRadius: 4,
    cursor: 'pointer'
  }
};

export default AIChatWindow;

三、关键逻辑扩展

  1. 对接真实 AI 接口
    getAIResponse 替换为接口请求(如使用 fetchaxios):

    const getAIResponse = async (userInput) => {
      const response = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${你的API密钥}`
        },
        body: JSON.stringify({
          model: 'gpt-3.5-turbo',
          messages: [{ role: 'user', content: userInput }]
        })
      });
      const data = await response.json();
      return data.choices[0].message.content;
    };
    
  2. 加载状态优化
    可添加“打字机效果”,让 AI 回复逐字显示,增强真实感:

    // 替换AI消息更新逻辑
    const aiResponse = "AI的完整回复内容";
    let currentIndex = 0;
    const interval = setInterval(() => {
      currentIndex++;
      setMessages(prev => {
        const newMessages = [...prev];
        newMessages.pop();
        newMessages.push({ 
          role: 'ai', 
          content: aiResponse.slice(0, currentIndex), 
          loading: currentIndex < aiResponse.length 
        });
        return newMessages;
      });
      if (currentIndex >= aiResponse.length) clearInterval(interval);
    }, 50); // 每50ms显示一个字
    
  3. 历史记录持久化
    使用 localStorage 保存对话记录,刷新页面后恢复:

    // 初始化时读取本地存储
    useEffect(() => {
      const savedMessages = localStorage.getItem('aiChatHistory');
      if (savedMessages) setMessages(JSON.parse(savedMessages));
    }, []);
    
    // 对话更新时保存到本地存储
    useEffect(() => {
      localStorage.setItem('aiChatHistory', JSON.stringify(messages));
    }, [messages]);
    

四、总结

核心逻辑围绕“状态管理”和“交互流程”:

  • 用 React 状态存储对话记录和用户输入;
  • 通过事件处理函数完成消息发送、AI 响应触发;
  • 动态渲染对话列表并优化用户体验(自动滚动、加载状态)。

根据需求可扩展为多轮对话、消息编辑、文件上传等功能。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐