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

如何在React中使用map方法向textarea添加动态内容并实现自动滚动

问题根因

  • <textarea>的value属性仅支持纯字符串输入,你传入JSX元素数组时,React会自动调用对象的toString()方法,所以会输出[object Object]。同时textarea本身不支持渲染内部HTML标签、自定义样式类,你写的small、p标签都无法在textarea内生效。
  • 你当前的时间生成逻辑存在问题:放在组件顶层的时间会在每次组件重渲染时刷新所有消息的时间,无法保留每条消息实际接收的时间戳。
  • 原代码中部分DOM属性写了class,React规范需要用className,否则会出现属性不生效的警告。

解决方案

方案1:用可滚动div替代textarea(推荐,支持自定义样式)

这是最优解,既能保留你需要的消息样式,也能轻松实现自动滚动效果,修改后代码如下:

import { Fragment, useEffect, useRef } from "react";
import { format } from "date-fns";
const Chat = ({ name, message }) => {
  // 绑定聊天容器的ref用于控制滚动
  const chatLogRef = useRef(null);

  // 监听消息数组变化,新消息进来时自动滚动到底部
  useEffect(() => {
    if (chatLogRef.current) {
      chatLogRef.current.scrollTop = chatLogRef.current.scrollHeight;
    }
  }, [message]);

  return (
    <Fragment>
      <div>
        <h3 className="d-inline-block me-3"> Chat log </h3>
        {name && (
          <span className="me-3 d-inline-block">
            <div
              className="spinner-grow spinner-grow-sm text-success"
              style={{ fontSize: "10px" }}
              role="status"
            >
              <span className="visually-hidden">Loading...</span>
            </div>
          </span>
        )}
        <small className="text-muted d-block"> {name}</small>
        {/* 模拟textarea样式的可滚动div */}
        <div
          ref={chatLogRef}
          style={{
            width: "fit-content",
            height: "160px",
            border: "1px solid #ced4da",
            borderRadius: "0.25rem",
            padding: "0.375rem 0.75rem",
            overflowY: "auto",
            backgroundColor: "#fff"
          }}
        >
          {message.map((eachMsg, index) => {
            // 建议在socket接收消息时就把时间存入消息对象,避免重渲染刷新所有时间
            // 这里用你引入的date-fns格式化时间,比手动拼接更简洁
            const timeStr = format(new Date(), 'HH:mm:ss')
            return (
              <Fragment key={index}>
                <small className="text-muted d-inline-block">{timeStr}</small>
                <p
                  className="d-block shadow p-1 fw-bold rounded text-success"
                  style={{ fontFamily: "cursive" }}
                >
                  {eachMsg}
                </p>
              </Fragment>
            );
          })}
        </div>
      </div>
    </Fragment>
  );
};

export default Chat;

方案2:必须使用textarea的处理方式

如果业务要求必须用textarea,就需要放弃自定义样式,把所有内容拼接为纯字符串传入value:

<textarea
  ref={chatLogRef}
  cols="70"
  rows="8"
  value={message.map(eachMsg => {
    const timeStr = format(new Date(), 'HH:mm:ss')
    return `${timeStr}\n${eachMsg}\n`
  }).join('')}
></textarea>

自动滚动逻辑和方案1一致,给textarea绑定ref后在useEffect中控制滚动位置即可。


优化建议

建议你在接收到socket消息存入数组时,就把当前时间一起存到消息结构中,比如每条消息格式为{ content: '消息内容', time: new Date() },这样历史消息的时间不会随着组件重渲染被覆盖。

内容的提问来源于stack exchange,提问作者nodeDev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:48:03