React display line breaks from saved textarea

Using Facebook React. In a settings page, I have a multiline textarea where a user can enter multiline text (in my case, an address).

<textarea value={address} />

When I try to display the address, so something like {address}, it doesn't show the line breaks and is all on one line.

<p>{address}</p>

Any ideas how to solve this?

94502 次浏览

This is to be expected, you would need to convert the new line (\n) characters to HTML line breaks

An article about using it in react: React Newline to break (nl2br)

To quote article:

Because you know that everything in React is functions, you can't really do this

this.state.text.replace(/(?:\r\n|\r|\n)/g, '<br />')

Since that would return a string with DOM nodes inside, that is not allowed either, because has to be only a string.

You then can try do something like this:

{this.props.section.text.split(“\n”).map(function(item) {
return (
{item}
<br/>
)
})}

That is not allowed either because again React is pure functions and two functions can be next to each other.

tldr. Solution

{this.props.section.text.split(“\n”).map(function(item) {
return (
<span>
{item}
<br/>
</span>
)
})}

Now we're wrapping each line-break in a span, and that works fine because span’s has display inline. Now we got a working nl2br line-break solution

There's no reason to use JS. You can easily tell the browser how to handle newline using the white-space CSS property:

white-space: pre-line;

pre-line

Sequences of whitespace are collapsed. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes.

Check out this demo:

<style>
#p_wrap {
white-space: pre-line;
}
</style>


<textarea id="textarea"></textarea>
<p id="p_standard"></p>
<hr>
<p id="p_wrap"></p>
<script>
textarea.addEventListener('keypress', function(e) {
p_standard.textContent = e.target.value
p_wrap.textContent = e.target.value
})
</script>

browser support

The solution is to set the property white-space on the element displaying the content of your textarea:

white-space: pre-line;

As of React 16 a component can return an array of elements, which means you can create a component like this:

export default function NewLineToBr({children = ""}){
return children.split('\n').reduce(function (arr,line) {
return arr.concat(
line,
<br />
);
},[]);
}

which you'd use like this:

<p>
<NewLineToBr>{address}</NewLineToBr>
</p>

Pete's previous proposal with standalone component is great solution although it misses one important thing. Lists needs keys. I adjusted it a bit and my version (without console warnings) looks like this:

const NewLineToBr = ({ children = '' }) => children.split('\n')
.reduce((arr, line, index) => arr.concat(
<Fragment key={index}>
{line}
<br />
</Fragment>,
), [])

It uses React 16's Fragments

Love webit version. I did not know about the Fragment component, it is so useful. No need to use the reduce method though. Map is enough. Also, list do need keys in react , but it is bad habit to use index from the iterating method for it. eslint kept on smashing this in my warning until I had the confusion bug. So it'd look like this :

const NewLine = ({ children }) =>
children.split("\n").map(line => (
<Fragment key={uuidv4()}>
{line}
<br />
</Fragment>
));

A small addition to answers above: white-space property should better be used with word-wrap to prevent overflowing.

p {
white-space: pre-wrap;
word-wrap: break-word;
}