Daniel Thompson
Daniel Thompson

Reputation: 2351

React render array of strings and JSX

I want to render JSX like the following:

<p>
    Some text with a <span> match </span> in it
</p>

My thought is to prepare data like this:

var text = ["Some text with a", <span>match</span>, "in it"]
return <p> {text} </p>

But this leads to problems with React keeping track of iterated children lacking keys.

Each child in an array or iterator should have a unique "key" prop.

Any idea how I could solve this problem?

Edit: to give some sense for how this is used, check out the following function stub:

/**
 * prepares string with JSX span tags to assist with highlighting of search result matches 
 * @param {string} name string to find the match within
 * @param {string} matchString the search query string that we are highlighting against
 * 
 * @returns {Array} an array containing characters and JSX for syntax highlighting
 */
export const matchHighlighting = (name, matchString) => {...}

I know the search query and the response text and want to display to the user highlights -- I essentially attempted to write a function that would interpolate the contents of a string with span tags where necessary, leaving me with an array similar to the example that I posted at the top.

This react issues thread kind of highlights the problem; sounds like it's a tough one that hasn't really found a good solution?

Upvotes: 6

Views: 12306

Answers (3)

Satyaki
Satyaki

Reputation: 751

To solve the issue related to key, you need to put key attribute on each of the array elements. To do this, instead of

<p> {text} </p>

we need to iterate over the array, like this -

{text.map((el,index)=> {<p key={index}>{el}</p>})}

Upvotes: 3

devserkan
devserkan

Reputation: 17638

I've used @sophiebit's solution here. Seems working :)

const matchHighlighting = (name, matchString) => {
  const re = new RegExp(`(\\b${matchString}+\\b)`, 'gi');
  const parts = name.split(re);
  for (var i = 1; i < parts.length; i += 2) {
    parts[i] = <span className="match" key={i}>{parts[i]}</span>;
  }
  return <div>{parts}</div>;
}

const name = "Some text with a, match in it";
const matchString = "match";

class App extends React.Component {
  render() {
    return <div>{matchHighlighting(name, matchString)}</div>;
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
.match {
  color: red;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 2

Davit Yavryan
Davit Yavryan

Reputation: 298

Use React Fragments (introduced in React v16.0). Here is link to documentation

<React.Fragment>Some text with a <span>match</span> in it</React.Fragment>

p.s. Also why not just put inside of <p>?

Upvotes: 0

Related Questions