Reputation: 2029
I have a text file that I'm reading as a string, and then inserting into the DOM like so:
//the state gets set with the contents of a text file that has proper indentation
state = {
parsedText: null
}
//in the render function, this is how the text comes in
<p>{this.state.parsedText}</p>
When I iterate through the character codes, I can see that the 'enter' codes (i.e., 13) seem to work when I console.log the file (the indentation looks correct). Unfortunately, those character codes don't translate to HTML - the entire string just comes out as one solid chunk of text. So, what I'm trying to do is insert either <br>
tags or \n
characters or
in order to make the breaks work in the HTML.
Here's what that looks like:
rawFile.onreadystatechange = () => {
if (rawFile.readyState === 4) {
if (rawFile.status === 200 || rawFile.status == 0) {
let allText = rawFile.responseText;
for (let i = 0; i < allText.length; i++) {
let uni = allText.charCodeAt(i)
if (uni === 13) {
console.log('enter!!')
allText = allText.substring(0, i) + "\n" + allText.substring(i + 1, allText.length - 1)
}
}
console.log("allText: ", allText);
console.log(typeof allText)
this.setState({
parsedText: allText
});
}
}
};
rawFile.send(null);
}
The \n
insertions show up in the text string but are seemingly just ignored in the DOM. Is there a way to make this work? I've tried dangerouslySetInnerHTML and that does nothing.
Any ideas on how to make this work?
Upvotes: 8
Views: 31846
Reputation: 800
Had the same issue. just solved it.
All you need to do is to save the string as array. like so:
let text = "this is text without break down \n this won't work but will be one line"
let text = ["this is text with breakdown",
<br/>,
"this is the second line"];
You can also write utility function to do that for you:
const addLineBreak = (str: string) =>
str.split('\n').map((subStr) => {
return (
<>
{subStr}
<br />
</>
);
});
And use it:
<p>{addLineBreak("Hello \n World"}</p>
Here's an example on StackBlitz for your reference.
Hope that helps
Upvotes: 24
Reputation: 8626
If you want to print a <br/>
tag in react I wanted to point out that a neat workaround is to use the <Trans>
component from i18next.
If you have a variable like this:
const customInviteMessageByCreator = "DEMO APPOINTMENT<br/>This room is to test your video room.";
You can write your variable wrapped in a Trans component like so:
<Trans>{customInviteMessageByCreator}</Trans>
And then it replaces the whitelisted html elements that you can configure in your i18n.js file like this:
transKeepBasicHtmlNodesFor: ["br", "strong", "b", "i"],
I didn't read that this is possible but I was curious if it works because i18next also translates our linebreaks in the translation.json and indeed it does.
I think it is a less hacky and more reliable method than what I've found so far like doing a map on <br>
where there could be a / before the >. Plus you can whitelist more than just linebreaks. And of course a smarter choice over dangerouslySetInnerHtml.
Upvotes: 0
Reputation: 2058
If possible, avoid using dangerouslySetInnerHTML
.
An alternate solution could be splitting your text into an array then rendering a new div
for each "newline".
Of course, you would need to come up with a better key
for the text, as there could be duplicate text - though that is a separate question in and of itself.
class Hello extends React.Component {
constructor(props) {
super(props)
this.state = {
parsedText: [
"Some text",
"More text",
"Keep on texting"
]
}
}
render() {
return <div>{this.state.parsedText.map(text => <div key={text}>{text}</div>)}</div>;
}
}
ReactDOM.render(
<Hello/>,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Upvotes: 2
Reputation: 2029
So you need to dangerouslySetInnerHTML, and as was pointed by FrV, the answer is to insert a <br />
... turns out I was missing the closing "/". Whoops. Hope this helps somebody running into a similar problem.
Upvotes: -1