I'm porting a small side project from Flask + server-side template rendering to Flask + React. One component uses a Jinja2 custom filter, nl2br, that simply translates newlines in plaintext to <p>
and <br>
tags in HTML. I'd like to implement something similar in idiomatic Javascript (with a focus on React).
I think the key step I'm missing is a way to manually perform the same escaping that React applies to string variables in JSX. Is that exposed anywhere?
The original Python code:
import re
from jinja2 import evalcontextfilter
from markupsafe import Markup, escape
_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
@evalcontextfilter
def nl2br(eval_ctx, value):
result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', Markup('<br>\n'))
for p in _paragraph_re.split(escape(value)))
if eval_ctx.autoescape:
result = Markup(result)
return result
Outline of the code: 1. escape the input, 2. split it into paragraphs ( <p>
) based on pairs of newlines, 3. replace newlines inside paragraphs with <br>
tags, and 4. wrap with Markup
if configuration demands HTML output and use the @evalcontextfilter
decorator to disable unwanted autoescaping beyond that.
The middle two steps can be translated directly to Javascript (just regexp and string processing). I think the React analogue of the last step is to use dangerouslySetInnerHTML
. But I can't figure out a good way to perform the first. There are all sorts of HTML escaping libraries on NPM but I'd like to use React's built-in escaping for consistency if possible.
This can be implemented in a slightly different way in React by just escaping the individual strings after building the DOM tree instead of escaping everything before splitting as in the Python code:
const _p_re = /((?:\r\n|\n){2,})/;
const _br_re = /(\r\n|\r|\n)/;
function nl2br(text) {
if (text === "") return <p />;
let ps = text.split(_p_re);
for (let i = 0; i < ps.length; i += 2) {
const p = ps[i];
let parts = p.split(_br_re);
for (let j = 0; j < parts.length; j += 2) {
parts[j] = <React.Fragment key={j}>{parts[j]}</React.Fragment>
}
for (let j = 1; j < parts.length; j += 2) {
parts[j] = (
<React.Fragment key={j}>
<br />
{parts[j]}
</React.Fragment>
);
}
ps[i] = <p key={i}>{parts}</p>;
}
return <>{ps}</>;
}
NB: I don't think this code uses the key
prop correctly, as I don't quite understand that at the moment. But it works for my purposes.
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.