Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I generate dynamic React markup

I'm trying to convert the output from a free text comment field into a formatted component. I have an array of substitution strings which I would like to replace within the text and attach click handlers to as well. I'm struggling to think of a nice way to do it, I don't really want to go down the dangerouslySetInnerHTML route if possible. Here's what I started to work on but didn't get very far with:

  const FormattedComment = () => {
    const comment = 'Some info about 1A and 2A... maybe 1A again.';
    const substitutions = ['1A', '2A', '3A'];
    const subPostions: { sub: string; pos: number }[] = [];

    for (const sub of substitutions) {
      // this won't handle duplicates :(
      const pos = comment.indexOf(sub);
      if (pos >= 0) {
        subPostions.push({ sub, pos });
      }
    }

    // do something here (map? forEach?)
  };

In the hope that I could produce something like this (or better):

  <>
    <span>Some info about </span>
    <strong onClick={() => {}}>1A</strong>
    <span> and </span>
    <strong onClick={() => {}}>2A</strong>
    <span>... maybe </span>
    <strong onClick={() => {}}>1A</strong>
    <span> again.</span>
  </>

Any suggestions or working examples would be much appreciated.

like image 826
tomblackwell Avatar asked Apr 07 '26 21:04

tomblackwell


1 Answers

You need to use regular expressions for doing this. I created a sandbox for it: https://codesandbox.io/s/intelligent-sea-tfxpk?file=/src/App.js

EDIT:

I updated my solution. It's much simpler now works great. Additionally, it is a better approach from a performance standpoint as it does not create an array from all the words in the string, but only from those that are needed.

let comment = "Some info about 1A and 2A maybe 1A again.";
  const substitutions = ["1A", "2A", "3A"];

  const parts = comment.split(
    new RegExp(
      String.raw`(\b${String(substitutions).replaceAll(",", "|")}+\b)`,
      "gi"
    )
  );

  for (let i = 1; i < parts.length; i += 2) {
    parts[i] = <strong key={i}>{parts[i]}</strong>;
  }

  return <div className="App">{parts}</div>;
like image 64
Bart Krakowski Avatar answered Apr 09 '26 09:04

Bart Krakowski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!