0

Based on a function I've seen here I am trying to build a component that highlights every word from an array I'll provide, inside the string I give it.

For example, if I'll use it like this:

  <Highlight
    body="Hi there stack overflow, hope you're all well"
    items={["there", "hope"]}
  />

What I'd like to get back is:

Hi there stack overflow, hope you're all well

So sometimes it works, and other times it doesn't, and I can't figure out the pattern.

Using the example string, if I'll give it this array ["there"] then I'll get it correctly printing:

Hi there stack overflow, hope you're all well

If I'll give it this array ["there", "hope"] then I'll get it correctly printing:

Hi there stack overflow, hope you're all well

BUT if I'll give it this array ["there", "hope", "overflow"] then I'll get this weird string:

Hi there stack overflow, hopeoverflowoverflowoverflow, hope you're all well

This is my function currently:

const highlightWords = (source, target, callback) => {
  if (!source) return res;
  if (!target) return source;

  const defaultHighlight = s => <em key={Math.random(1000)}>{s}</em>;
  const res = [source];

  let lastOffset = 0;

  target.forEach(element => {
    res.forEach(stringEl => {
        console.log(typeof stringEl)
      if (typeof stringEl === typeof "")
        // Uses replace callback, but not its return value
        stringEl.replace(new RegExp(element, "gi"), (val, offset) => {
          // Push both the last part of the string, and the new part with the highlight
          res.push(
            stringEl.substr(lastOffset, offset - lastOffset),
            // Replace the string with JSX or anything.
            (callback || defaultHighlight)(val)
          );
          lastOffset = offset + val.length;
        });
    });
  });

  // Push the last non-highlighted string
  res.push(source.substr(lastOffset));
  res.shift();
  return res;
};

And this is my component:

export const Highlight = ({ body, items}) => {
  return (
    <div>
      {highlightWords(body, items, s => (
        <span className="bold-700" key={Math.random(1000)}>
          {s}
        </span>
      ))}
    </div>
  );
};
Tsabary
  • 3,119
  • 2
  • 24
  • 66
  • 1
    Just a guess, but you are modifying the `res` while working on it and the overflow word comes before hope in input body, that might be messing up. What happens if you give array `["there", "overflow", "hope"]` array as the items? Does it still mess up the result? – Sunil Chaudhary Jan 30 '20 at 11:28
  • @Sunil Yes that it! I've resorted to using an external package that provides me more stuff than I care building at this point, but you're spot on. As soon as I give it the words in the right order everything works right. Submit it as an answer and I'll approve it. – Tsabary Jan 30 '20 at 11:39

0 Answers0