2

I am building a search component, and for each possible auto suggestion, I'd like to highlight where the searched term appears.

I've found this and I've been trying to use regex to achieve my desired result, but I think something in the way components works prevent it from working, and I can't figure out how to get it to work.

Here's what I am trying to do:

var reg = new RegExp(searchTerm, "gi");


return (
  <div className="single-result">
      {result.name.replace(reg, searchTerm => {
        return <div className="single-result__bold"> {searchTerm}</div>;
      })}
  </div>
);

But what I get printed looks like this:

[object Object]A[object Object]d[object Object]a[object Object]l[object Object]i[object Object]n[object Object]e[object Object] [object Object]A[object Object]r[object Object]r[object Object]a[object Object]u[object Object]l[object Object]t[object Object]
Tsabary
  • 3,119
  • 2
  • 24
  • 66
  • You can assign the result string to a variable, say `innerHtml` and use `dangerouslySetInnerHtml` to parse it into actual DOMs. Your current code is just returning a string and displaying it inside a div, so won't render DOMs. – technophyle Jan 29 '20 at 16:49
  • 3
    Does this answer your question? [How to highlight matches within a string with JSX?](https://stackoverflow.com/questions/57597563/how-to-highlight-matches-within-a-string-with-jsx) – Emile Bergeron Jan 29 '20 at 16:51
  • Most JavaScript-only answers will fail with JSX since they're building HTML strings which are either not working well in JSX or just inefficient. – Emile Bergeron Jan 29 '20 at 16:52
  • @EmileBergeron on first glance I believe your answer in the other post is what I am looking for. Trying to implement it – Tsabary Jan 29 '20 at 16:53

2 Answers2

4

The replace function is not built for use with JSX, and is converting your virtual DOM nodes to strings.

This overload of string.replace expects its second argument to be a function returning a string (and if not, it converts it to a string). In this case, you're returning a JSX node from this function, which appears as [object Object] when it's put through .toString() - the replace function then joins the unmatched strings with the outputs from the function, which is the string you show above. This dodgy string is what is output to React, and so that's what it renders.

Instead, you could use repeated calls to string.search (or at a lower level, regex.match) to find out the index of each matches (and the matches themselves), and then output an array of the unmatched text and DOM nodes for the matched text.

Such an array might look like:

[
   "This text surrounds a ",
   <div className="single-result__bold">match</div>,
   ", but is still in a normal text node"
];

The above array can then be rendered in react/JSX and will appear as you expect.

David E
  • 1,384
  • 9
  • 14
2

I think you can use react-string-replace like this:

const generateHighlightedText = (caption, searchValue) =>
  searchValue
    ? reactStringReplace(caption, searchValue, (match, i) => (
        <Highlighted key={i}>{match}</Highlighted>
      ))
    : caption;

link: https://github.com/iansinnott/react-string-replace

Gabda
  • 56
  • 4