Reputation: 2351
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
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
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
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