React js - 将事件侦听器添加到 html 字符串

React js - Add an event listener to an html string

我正在 React js 上开发一个聊天应用程序,我有以下内容:

{messages.map((chat, index) => {
  return (
   <p className="ctext" id={chat.id} dangerouslySetInnerHTML={{ __html: 
  chat.body.replace(/\B(\#[a-zA-Z0-9]+\b)/g, match => `<span className="linkHashtag" onclick={hashTagClicked(${match})}>${match}</span>`) }}>
   </p>
  )
})}

所以基本上,我有一个消息映射,我将 HTML 字符串中的所有标记替换为 class 并尝试添加一个函数(运行时),但是当我尝试这个时,函数像字符串而不像函数:

<span class="linkHashtag" onclick="{" clicktagsearch(#MARKET)="" }="">#MARKET</span>

有什么想法吗?

编辑:

我认为这是无需直接操作 DOM 即可获得相同结果的更好方法:

const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;    

const DeclarativeRendering = ({ handler }) => (
      <div>
        {messages.map((chat, index) => {
          return (
            <p className="ctext" id={chat.id}>
              <TaggedString
                str={chat.body}
                onClick={handler}
                style={{ marginRight: '5px' }}
                className="linkHashtag"
              />
            </p>
          );
        })}
      </div>
    );
    
    
    const makeTag = (txt, props) => {
      return <span {...props}>{txt}</span>;
    };
    
    const TaggedString = ({ str, ...props }) => {
      const stringsArray = useMemo(
        () =>
          str
            .split(' ')
            .map((el) => (reg.test(el) ? makeTag(el, props) : el + '\n')),
        [str, props]
      );
      return stringsArray;
    };

您可以在此处测试这两种方法:https://stackblitz.com/edit/react-u7k6od?file=src%2FApp.js

// 旧答案

我认为由于拼写错误(HTML 和 JSX 以不同的方式声明属性)样式不起作用,并且事件侦听器不起作用,因为您需要将它们手动附加到 DOM渲染后的节点,像这样的东西应该可以工作:

const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;

const ImperativeManipulation = ({ handler }) => {


const handleEl = (el) => {
    if (!el) return;
    el.querySelectorAll("span").forEach((child) => (child.onclick = handler));
  };

  return (
    <div ref={handleEl}>
      {messages.map((chat, index) => {
        const newText = chat.body.replace(reg, match => `<span class="linkHashtag">${match}</span>` )
        return (
          <p
            className="ctext"
            id={chat.id}
            dangerouslySetInnerHTML={{
              __html: newText,
            }}
          ></p>
        );
      })}
    </div>
  );
};

但我认为有更好的方法来实现这一点,避免完全命令式 DOM 操作,这是一种 React 反模式。

注意: 为了避免在重新挂载时发生内存泄漏,我使用 .onclick 语法来附加事件侦听器,因此每次重新挂载组件时它们都会被简单地覆盖,如果你想将 eventListener 附加到节点,你必须确保在卸载时清理它,所以你需要使用 useEffect 来处理这个逻辑。