The problem as you pointed out is with String.prototype.replace. It expects the second parameter to be either a string, or a function that returns a string. It will always take an object (like a jsx
) and simply convert it, so that it ends up being [object Object]
.
I believe the only way you could continue using .replace
would be to use the react dangerouslySetInnerHTML
escape hatch. This is almost always a really bad idea, but if you feel you really must...look at your own peril.
// This code snippet won't actually run; I only used a snippet so I could hide it
const listItems = content.content.map((result, index) => (
<li key={index} dangerouslySetInnerHTML={{
__html:
Object.keys(parameters).reduce((res, key) => {
return res.replace(`#${key}#`, `<span>${parameters[key]}</span>`);
}, result.text)
}}>
</li>
));
A way that wouldn't require using something with dangerous
in the name:
function safeReplace(string) {
// split the string on #word# patterns, keeping the patterns
return string.split(/(#\w+#)/g)
// filter out any empty strings
.filter(x => x.length > 0)
.map(x => {
const m = /#(\w+)#/.exec(x);
// if it's not of the form #word#, just return the string fragment
if (!m) return x;
const repl = parameters[m[1]];
// if the pattern actually matches a parameter, wrap with span
if(repl) return <span>{repl}</span>;
// if pattern doesn't match a paraemter, return string fragment.
return x;
});
}
const listItems = content.content.map((result, index) => (
<li key={index}>
{safeReplace(result.text)}
</li>
));
I incorporated this method into a fiddle to show it in action.
*Edit: @Thomas suggests a really cool, more efficient, and more succinct method.
With split
, every odd indexed array member will be a #word#
pattern. You can take advantage of that knowledge to have a much simpler map
statement that doesn't need to do a second regex match:
function safeReplace(string) {
return string.split(/#(\w+)#/g)
.map((x,i) => (i&1) ? (<span>{parameters[x]}</span>) : x)
.filter(x => x.length > 0);
}
- He's using a bitwise operator to determine if
i
is odd.
- Note, we also have to move the capture parentheses in the
split
so that the leading and trailing #
characters are not included.
- Also, if there are any occurrences of
#word#
that don't correspond to a parameter replacement, this wouldn't work. You'd have to use the more verbose method above, (or use a nested ternary expression to check if parameters[x]
is defined)