Search code examples
javascriptreactjsdangerouslysetinnerhtml

Passing a function to a button within dangerouslySetInnerHTML doesn't work


I am trying to add a button tag between a text when a pattern is found in react, this is done inside the dangerouslySetInnerHTML attribute. The onClick only works with alert() and console.log(), it doesn't work when I passed a function to it. What am I missing?

    export const detectHashTagPattern = (text) => {
      if(!text) return '';
      let pattern = /This is a follow-up to your previous request #[0-9]+/gi;
      let hashTagPattern = /#[0-9]+/;
    
      text = text.replace(pattern, (res) => {
        return res.replace(hashTagPattern, `<button onClick={}>${hashTagPattern.exec(res)}</button>`);
      });

  return text;
};

Solution

  • Well you could change the algorithm like the following:

    
    function clickHandler() {
      console.log("do something");
    }
    
    window.clickHandler = clickHandler;
    
    export const detectHashTagPattern = (text) => {
      if (!text) return "";
      let pattern = /This is a follow-up to your previous request #[0-9]+/gi;
      let hashTagPattern = /#[0-9]+/;
    
      text = text.replace(pattern, (res) => {
        return res.replace(
          hashTagPattern,
          // use window.<fct>()
          `<button onClick="window.${window.clickHandler.name}()">${hashTagPattern.exec(
            res
          )}</button>`
        );
      });
    
      return text;
    };
    
    

    You shouldn't go with this approach, as it might have other issues with the rendering in your application (depends what you're doing in the handler).

    A better approach would be like this:

    const splitSubject = (text) => {
      if (!text) {
        return [""];
      }
    
      let pattern = /This is a follow-up to your previous request #[0-9]+/gi;
    
      if (!pattern.test(text)) {
        return [text];
      }
      let hashTagPattern = /#[0-9]+/;
      let result = text.search(hashTagPattern);
      return [text.slice(0, result), text.slice(result), text.slice(result + 1)];
    };
    
    const Subject = ({ subject, handler }) => {
      const splitted = splitSubject(subject);
    
      let content = null;
      if (splitted.length === 1) {
        content = <span>{splitted[0]}</span>;
      } else {
        let [info, cmd, reqReference] = splitted;
    
        content = (
          <>
            <span>{info}</span>
            <button onClick={() => handler?.(reqReference)}>{cmd}</button>
          </>
        );
      }
    
      return <p>{content}</p>;
    };
    
    export default function App() {
      const requestHandler = (num) => {
        console.log(`click on '${num}'`);
      };
    
      return (
        <div>
          <Subject
            handler={requestHandler}
            subject="This is a follow-up to your previous request #9"
          />
          <Subject handler={requestHandler} subject="Not matching subject" />
        </div>
      );
    }