3

So i'm making a React app that fetches lyrics of songs from an API

The API gives me a lyrics_body that is a string and i'm using that to display the lyrics on the page, problem is, that it's not particularly nice to look at when react renders it because the api gives me this:

They say "Oh my god I see the way you shine"↵Take your hand, my dear(This is part of the lyrics data that the API gives me back)

It's this character: that pose a problem, it's nice of them to give me anything at all that is supposed to be a linebreak. So i decided to replace that character with a <br />

This is a piece of my code:

<div className="card-body">
   <p className="card-text">
      {lyrics.lyrics.lyrics_body.replace(/(\r\n|\n|\r)/gm, "<br />")}
   </p>
</div>

That will obviously not put a line break but it will just render <br /> directly into the paragraph and that's no good

I'm quite new to JSX and what you can and can't do with it so i'm kind of lost here, i tried /n or %0D%0A or any other thing i found during my research but nothing worked

I also tried concatenating via adding a variable like that:

const newLine = <br />;

<div className="card-body">
   <p className="card-text">
      {lyrics.lyrics.lyrics_body.replace(/(\r\n|\n|\r)/gm, `${newLine})}
   </p>
</div>

But that just renders like that:

They say "Oh my god I see the way you shine"[object Object]Take your hand, my dear

TLDR: How can i insert a line break anywhere where there is a ↵ ? I would be done with it if not for the JSX expression.

I think i need to learn more about JSX

scorpio
  • 35
  • 1
  • 5

5 Answers5

9

You can avoid this whole ordeal with CSS:

.card-text {
    white-space: pre-line;
}

This will cause the text to wrap on line breaks (and when necessary).

Just render the lyrics_body as is:

<p className="card-text">
    {lyrics.lyrics.lyrics_body}
</p>
Tarnay Kálmán
  • 6,907
  • 5
  • 46
  • 57
5

Maybe it's an idea to split the string and map over it?

lyrics.lyrics.lyrics_body.split(/\r\n|\n|\r/gm).map(line => {
    return <React.Fragment>{line}<br /></React.Fragment>
})
forkerino
  • 123
  • 9
  • This splits the string received from the API and maps over the array of substrings and then returns it with a
    at the end. It works nicely but still looks off with how much white space is rendered but i think it's the best i'm gonna get with what i have to work with to be honest. Don't know why i didn't think of that, thanks.
    – scorpio Jan 03 '20 at 10:21
3

It might be more idiomatic if you split on the newline and then map over the lines with a p element.

const lines = lyrics.split(/(\r\n|\n|\r/)

{lines.map(line => <p>{line}</p>)}

Brennan Cheung
  • 4,271
  • 4
  • 30
  • 29
2

Use "dangerouslySetInnerHTML" to render the <br/>

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it’s dangerous. For example:

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

Reference: https://reactjs.org/docs/dom-elements.html

user54987
  • 112
  • 8
  • I've seen that when i researched on my problem but i'd rather avoid using that because of how risky it is. I doubt i'll get a lot of users because this is for my portfolio, but i rather not rely on it right now than trying to get rid of my reliance later. But thank you. – scorpio Jan 03 '20 at 09:31
0

Too low reputation to upvote or comment, but the answer from Tarnay Kálmán worked a charm for me. Using CSS avoids the hassle of reformatting the string. Add a CSS class with 'white-space: pre-line' to the DOM element containing the text you want to render with linebreaks:

CSS:

.card-text {
    white-space: pre-line;
}

HTML:

<p className="card-text">
    {lyrics.lyrics.lyrics_body}
</p>