I have a React component , to whose props I want to assign a string that includes both JavaScript variables and HTML entities.
Some of the approaches I've attempted have resulted in the HTML entity being rendered escaped. For example, –
gets rendered literally as " –
" instead of as " –
".
Is there a way to get an HTML entity to render unescaped in a JSX dynamic content block being assigned to a React props?
Tried using a template literal :
<MyPanel title={`${name} – ${description}`}> ... </MyPanel>
Problem: In the rendered output, the –
is being rendered literally as " –
" instead of as " –
".
Attempted to construct some simple JSX with no quotes:
<MyPanel title={{name} – {description}} ... </MyPanel>
Problem: This failed at compile time with a syntax error.
Tried working around the syntax error by wrapping the JSX in a <span />
element:
<MyPanel title={<span>{name} – {description}</span>} ... </MyPanel>
Problem: This works, but I'd rather avoid the superfluous <span />
element being present in the rendered output.
Tried replacing the HTML entity with a Unicode numeric character reference:
<MyPanel title={name + ' \u2013 ' + description} ... </MyPanel>
Problems:
+
-operator concatenation, which triggers a Unexpected string concatenation prefer-template
error in my team's JSLint checker; a solution that uses string interpolation instead would be better.You can avoid the superfluous span
with a Fragment
:
<MyPanel title={<>{name} – {description}</>} ... </MyPanel>
This feature was introduced in React 16.2.
See the Documentation
I agree with @samanime that using the actual character is best for simple cases, but if your content is truly dynamic, I would prefer using a Fragment
over either the entityToChar
or dangerouslySetInnerHTML
approaches.
Here are a few options (I outlined these in a more general answer awhile back):
Easiest - Use Unicode
<MyPanel title={ `${name} – ${description}` } />
Safer - Use the Unicode number for the entity inside a Javascript string.
<MyPanel title={`${name} \– ${description}`} />
or
<MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
Last Resort - Insert raw HTML using dangerouslySetInnerHTML.
title={`${name} – ${description}`}
with:
<div dangerouslySetInnerHTML={{__html: props.title}}></div>
const MyPanel = (props) => { return ( <div>{props.title}</div> ) } const MyPanelwithDangerousHTML = (props) => { return ( <div dangerouslySetInnerHTML={{__html: props.title}}></div> ) } var description = "description"; var name = "name"; ReactDOM.render(<MyPanel title={`${name} – ${description}`} /> , document.getElementById("option1")); ReactDOM.render(<MyPanel title={`${name} \– ${description}`} /> , document.getElementById("option2")); ReactDOM.render(<MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} /> , document.getElementById("option3")); ReactDOM.render(<MyPanelwithDangerousHTML title={`${name} – ${description}`} /> , document.getElementById("option4"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script> <div id="option1"></div> <div id="option2"></div> <div id="option3"></div> <div id="option4"></div>
Here is React's documentation on HTML entities: JSX Gotchas
Of those, using the actual character instead of the HTML entity would be the best:
<MyPanel title={ `${name} – ${description}` } />
If you can't do that because the HTML entity is dynamic (it's not just a hard-coded en-dash), you could translate the entity. Here is a little function that can do that:
const entityToChar = str => {
const textarea = document.createElement('textarea');
textarea.innerHTML = str;
return textarea.value;
}
You then use it like this:
<MyPanel title={ entityToChar(`${name} – ${description}`) } />
Without knowing how <MyPanel />
works, I can only speculate that you could do something like the following:
<MyPanel title={`${name} – ${description}`}> ... </MyPanel>
MyPanel.js
render() {
const { title } = this.props;
return <div dangerouslySetInnerHTML={{ __html: title }} />;
}
Since you probably don't want to allow arbitrary URL in your title
prop, I'd be tempted to write myself a function that only handles turning character entities into their Unicode character equivalent. Sort of "HTML-lite." :-) There aren't that many named references , really; and the numeric ones are easy:
const named = {
"ndash": "–", // or "\u2013"
"mdash": "—", // or "\u2014"
"nbsp": " " // or "\u00A0"
// ...
};
// Obviously this is a SKETCH, not production code!
function convertCharEntities(str) {
return str.replace(/&([^ ;&]+);/g, (_, ref) => {
let ch;
if (ref[0] === "#") {
let num;
if (ref[0].toLowerCase() === "x") {
num = parseInt(ref.substring(2), 16);
} else {
num = parseInt(ref, 10);
}
ch = String.fromCodePoint(num);
} else {
ch = named[ref.toLowerCase()];
}
return ch || "";
});
}
Then use it when rendering that prop:
class Example extends React.Component {
render() {
return <div>{convertCharEntities(this.props.title || "")}</div>;
}
}
Full Live Example:
const named = { "ndash": "–", // or "\–" "mdash": "—", // or "\—" "nbsp": " " // or "\ " // ... }; // Obviously this is a SKETCH, not production code! function convertCharEntities(str) { return str.replace(/&([^ ;&]+);/g, (_, ref) => { let ch; if (ref[0] === "#") { let num; if (ref[0].toLowerCase() === "x") { num = parseInt(ref.substring(2), 16); } else { num = parseInt(ref, 10); } ch = String.fromCodePoint(num); } else { ch = named[ref.toLowerCase()]; } return ch || ""; }); } class Example extends React.Component { render() { return <div>{convertCharEntities(this.props.title || "")}</div>; } } ReactDOM.render( <Example title="Testing 1 2 3 — enh, you know the drill <script src='nefarious.js'><\\/script>" />, document.getElementById("root") );
<div id="root"></div><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>
Note that the tags were not output as tags, but the entities were handled.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.