How can I make new line string of Props used in react? - reactjs

I'm having trouble with new line breaks in strings.
parent
<SampleComponent title="One \n Two \n Three">
children
type SampleComponentProps = {
title: string;
};
export const SampleComponent: FC<SampleComponentProps> = ({
title,
}) => {
return (
<div style={whiteSpace:'pre-line'}>{title}</div>
);
};
display
One \n Two \n Three
I would expect
One
Two
Three

The following code should work
return ({title.split("\\n").map((line, index) => (
<React.Fragment key={index}>
{line}
<br />
</React.Fragment>
))})

You can solve this problem by setting HTML directly from React, just using html and css, no using JS regex, or convert string to array then output.
<div
style={{whiteSpace: 'pre'}}
dangerouslySetInnerHTML={{ __html: ' One \n Two \n Three' }}
></div>
this is the result
Reference link: dangerously set innerHTML

Related

Typescript React - use MouseEvents without passing it to child element

Can I use Mouse Events on whole React Element or I have to pass it to child element to get it work? After several functions components where I passed my handleEvent function I want to know if it's possible without getting a TypeScript error. My code is really simple
<Tile onHover={handleHover} name="Random name"/>
and Tile component
export const Tile: React.FC<{ name: string }> = ({ name }) => {
return (
<div className="tile-wrapper">
<h1 className="tile-header>
{name}
</h1>
</div>
)
}
What you want is to combine React.DOMAttributes<HTMLElement> with your custom props using an intersection. That will avail all the DOM events to your custom component, without having to manually pass it in.
export const Tile: React.FC<{ name: string } & React.DOMAttributes<HTMLElement>> = ({ name, ...events }) => {
return (
<div className="tile-wrapper" {...events}>
<h1 className="tile-header>
{name}
</h1>
</div>
)
}
As your Title component does not expect an onHover prop, it will just be ignored. The event you want to use is rather onMouseOver, which works on most HTML elements (according to documentation):
All HTML elements, EXCEPT: <base>, <bdo>, <br>, <head>, <html>, <iframe>, <meta>, <param>, <script>, <style>, and <title>
What you could do is the following, in the Title component:
export const Tile: React.FC<{ name: string, onHover: SomeType }> = ({ name, onHover }) => {
return (
<div className="tile-wrapper" onMouseOver={onHover}>
<h1 className="tile-header>
{name}
</h1>
</div>
)
}

insert or remove enclosing element based on ternary operator JSX

I am trying to make the <pre> tags appear in the code or not as I need them.
If the text is code I want the <pre> tags to exist
If the text is not code then I don't want them to exist
The below code changes depending on the value textIsCode = 1 then the <pre> tags are displayed as text. If I remove the quotes around the <pre> then the code does not work do I need a different escape character or am I trying to do something the wrong way?
const CodeContainerMolecule = (props) => {
return (
<section id={props.CodeContainerMolecule_Id}
className={props.CodeContainerMolecule_Style}>
{props.textIsCode === "1" ? '' : `<pre>`}
<p className="container_component_text">
{props.text}
</p>
{props.textIsCode === "1" ? '' : `</pre>`}
</section>
);
};
export default CodeContainerMolecule
Having the <pre/> tags as strings is pretty weird, you'd be better off saving the child in a variable, then just conditionally wrapping it. Something like this:
const CodeContainerMolecule = (props) => {
const child = (
<p className="container_component_text">
{props.text}
</p>
);
return (
<section id={props.CodeContainerMolecule_Id}
className={props.CodeContainerMolecule_Style}>
{props.textIsCode === "1" ? <pre>{child}</pre> : child}
</section>
);
};
export default CodeContainerMolecule
P.S. there's a difference between a JSX tag, and a string whose context is a JSX tag, they aren't the same
Nesting a <p> Paragraph inside a <pre>is not an ideal HTML formatting.
const CodeContainerMolecule = (props) => {
return (
<section id={props.CodeContainerMolecule_Id}
className={props.CodeContainerMolecule_Style}>
{props.textIsCode === "1" ? <p>{props.text}</p> :
(<pre> {props.text} </pre>)}
</section>
);
};
export default CodeContainerMolecule

React: Inserting a line break in localised text

I'm getting localised text from a JSON file and displaying it to the page, my problem is that the \n and <br> notations are being ignored.
I've made a code sandbox here to show how the text doesn't get put on more than one line.
import * as React from "react";
import { render } from "react-dom";
const App: React.FC = props => {
const Translations: {
[key: string]: {
fname: string;
};
} = {
en: {
fname: "I want to insert a break in this line of text so it shows on two lines \n doesnt work and <br> does either",
},
cn: {
fname: "我想在这一行文本中插入一个中断,以便在两行中显示\ n不起作用,而<br>可以",
}
};
const txt = Translations["en"];
return (
<div className="App">
<p>{txt.fname}</p>
</div>
);
};
const rootElement = document.getElementById("root");
render(<App />, rootElement);
In order to respect \n, you can add a style of white-space: pre-line or white-space: pre-wrap.
In React, it would look like this:
return (
<div className="App">
<p style={{ whiteSpace: "pre-line" }}>{txt.fname}</p>
</div>
);
Here is a forked sandbox.
use css property white-space: pre-line
<p style={{ whiteSpace: "pre-line" }}>{txt.fname}</p>
You could use dangerouslySetInnerHTML, however make sure to sanitize your input with smth like DOMPurify:
return (
<div className="App">
<p
dangerouslySetInnerHTML={{
__html: txt.fname
}}
/>
</div>
);
As mentioned in the comment, another way is to replace <br> with \n and add whiteSpace: "pre-line" css rule:
return (
<div className="App">
<p style={{ whiteSpace: "pre-line" }}>
{txt.fname.replace("<br>", "\n")}
</p>
</div>
);
Working sandbox.
You could always use JSX instead - it would look like this
en: {
fname: <p>"I want to insert a break in this line of text so it shows on two lines \n doesnt work and <br> does either"</p>
}
return (
<div className="App">
{txt.fname}
</div>
);

String Template in React JSX

I created a server and inserted some data in it, Now when I want to refer to that data, it's not displaying the name field, I used string templates to read the name field from the server and show it, but it's not working, is there something wrong with syntax?
this is my component in React :
const Rank = ({ name, entries }) => {
return(
<div>
<div className='white f3'>
{` ${name} , your current rank is ... `}
</div>
<div className='white f1'>
{entries}
</div>
</div>
);
}
{entries} displays right,but i dont receive any data for {name}.
Please note that string literals are part of ES6. If you've not configured the project correctly, the string literals will not work.
Try hoisting he string concatenation before return and use it directly in the JSX as:
const rankOutput = name + ', your rank ...';
And use it in JSX as:
{rankOutput}
So final code would look like this:
const Rank = ({ name, entries }) => {
const rankOutput = name + ', your current rank is ...';
return(
<div>
<div className='white f3'>
{rankOutput}
</div>
<div className='white f1'>
{entries}
</div>
</div>
);
}

How to render a multi-line text string in React

Suppose I have a text string that contains line-breaks, and I render it like this:
render() {
var text = "One\nTwo\nThree";
return <div>{text}</div>;
}
In HTML the line-breaks don't render as line-breaks. How should I do this in React? I don't want to convert to <br> tags and use dangerouslySetInnerHTML. Is there another way?
Make a new CSS-class
.display-linebreak {
white-space: pre-line;
}
Display your text with that CSS-class
render() {
const text = 'One \n Two \n Three';
return (
<div className="display-linebreak">
{text}
</div>
);
}
Renders with line-breaks (Sequences of whitespace will collapse into a single whitespace. Text will wrap when necessary). Like this:
One
Two
Three
You may also consider pre-wrap. More info here (CSS white-space Property).
You could try putting divs for each line
render() {
return (<div>
<div>{"One"}</div>
<div>{"Two"}</div>
<div>{"Three"}</div>
</div>);
}
Or
render() {
var text = "One\nTwo\nThree";
return (
<div>
{text.split("\n").map((i,key) => {
return <div key={key}>{i}</div>;
})}
</div>);
}
You could use CSS property "white-space: pre". I think this is the easiest way to handle this.
Try this one,
render() {
var text = "One\nTwo\nThree";
return <div style={{whiteSpace: 'pre-line'}}>{text}</div>;
}
Here the cleanest solution (afaik):
render(){
return <pre>
Line 1{"\n"}
Line 2{"\n"}
Line 3{"\n"}
</pre>
}
Instead of you can also use <div style={{whiteSpace:"pre"}}>, or any other html block element (like span or p with this style attribute)
You can use -webkit-user-modify: read-write-plaintext-only; in your div. It will format and understand things like \n and \p for instance.
You can make use of textarea tag of html, later you can add the styling to the textarea tag.
It pretty much solves your all issues including line breaks and tab spaces.
Cheerzz...
eg:
Your render will look something like below
render() {
var text = "One\nTwo\nThree";
return <textarea>{text}</textarea>;
}
Output:
One
Two
Three
You can safely run String.raw instead for this type of value.
const text = String.raw`One
Two
Three
`
render() {
return <div style={{ whiteSpace: "pre" }}>{text}</div>
}
You can also just use a <pre> tag which effectively does the same thing, but its less semantically clear if you're already using that for other purposes in your app.
<div style={{ whiteSpace: "break-spaces" }}> {JSON.stringify(state, null, " ")} </div>
We can use package name dedent to render multiline text:
const multilineText = `
This is line 1
This is line 2
This is line 3
`;
export default function App() {
return (
<>
<div style={{ whiteSpace: "pre-wrap" }}>{dedent(multilineText)}</div>
</>
);
}
We preferred having <br/>s instead and are using this simple function component in our TypeScript project:
import React, { FunctionComponent } from "react"
export const Multiline: FunctionComponent<{ text: string }> = ({ text }) => (
<>
{text.split(/\n|\r\n/).map((segment, index) => (
<>
{index > 0 && <br />}
{segment}
</>
))}
</>
)
Render your delimited text "My line one\nMy second line\nWhatevs..." inside a normal html textarea. I know it works because i just used it today ! Make the textarea readOnly if you must, and style accordingly.
this example in react.js component,
it will insert each line into a new div element by using (map , split) and it is a good example for comments/posts to support ltr/rtl style component at the same time and here is a simple example :
<div>
{ ' this is first line \n this is second line \n this is third line '.split('\n').map( line =>
<div key={ Math.random() * 10} dir="auto" style={{ textAlign: 'start'}}> {line} </div>
)}
</div>
also if your string data comming from API / react state you can use your string variable name as the follwing :
<div>
{ post_comments.split('\n').map( line =>
<div key={ Math.random() * 10} dir="auto" style={{textAlign: 'start'}}> {line} </div>
)}
</div>
this is just example , and change it based on your case/requirements.
and if you like you can replace div tag with p tag as per your request .
i hope this helpful for you

Resources