MessageInput.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. "use client";
  2. import { FormEvent, useEffect, useRef } from "react";
  3. interface MessageInputProps {
  4. value: string;
  5. onChange: (value: string) => void;
  6. onSubmit: () => Promise<void> | void;
  7. sending: boolean;
  8. }
  9. export function MessageInput({
  10. value,
  11. onChange,
  12. onSubmit,
  13. sending,
  14. }: MessageInputProps) {
  15. // 输入框引用,用于发送消息后自动聚焦
  16. const inputRef = useRef<HTMLInputElement>(null);
  17. // 记录上一次的 sending 状态,用于判断是否刚刚完成发送
  18. const prevSendingRef = useRef<boolean>(false);
  19. // 当发送状态从 true 变为 false 时(发送完成),自动聚焦到输入框
  20. useEffect(() => {
  21. // 如果上一次是发送中(true),现在是发送完成(false),说明刚刚发送完成
  22. if (prevSendingRef.current && !sending && inputRef.current) {
  23. // 使用 setTimeout 确保 DOM 更新完成后再聚焦
  24. // 这样可以避免在某些情况下聚焦失败
  25. setTimeout(() => {
  26. inputRef.current?.focus();
  27. }, 0);
  28. }
  29. // 更新上一次的 sending 状态
  30. prevSendingRef.current = sending;
  31. }, [sending]);
  32. const handleSubmit = async (event: FormEvent) => {
  33. event.preventDefault();
  34. if (sending) {
  35. return;
  36. }
  37. await onSubmit();
  38. // 注意:聚焦逻辑由 useEffect 处理,当 sending 从 true 变为 false 时会自动聚焦
  39. };
  40. return (
  41. <form
  42. onSubmit={handleSubmit}
  43. className="border-t border-gray-200 px-4 py-3 flex items-center gap-2 bg-white flex-shrink-0"
  44. >
  45. <input
  46. ref={inputRef}
  47. type="text"
  48. placeholder="输入消息..."
  49. value={value}
  50. onChange={(event) => onChange(event.target.value)}
  51. className="flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm"
  52. disabled={sending}
  53. />
  54. <button
  55. type="submit"
  56. disabled={sending || !value.trim()}
  57. className="px-4 py-2 bg-blue-500 text-white text-sm rounded-lg hover:bg-blue-600 transition-colors disabled:bg-blue-200 disabled:cursor-not-allowed"
  58. >
  59. {sending ? "发送中..." : "发送"}
  60. </button>
  61. </form>
  62. );
  63. }