I'm rendering some paragraphs using React. Inside those paragraphs there should be a span for footnotes. The best I got so far is that it rendered [object Object].
function ArticleItem() {
const articles = [
{
title: "title",
content: [
`Text based on this footnote <span>1</span>`,
`Another argument, here is my source <span>2</span>`
]
}
];
return (
<div className="article-container">
<h3> {articles[i].title} </h3>
{
articles[i].content.map(paragraph => (
<p>
{ paragraph }
</p>
)
}
</div>
);
}
Because you are creating a string with "<span>" instead of creating actual <span> HTML elements. What you are using is named jsx, which converts HTML tags to their corresponding document.createElement() (or similar, which in React has it own way).
If you want the content to be an HTML element and not a string, then create an HTML element:
function ArticleItem() {
const articles = [
{
title: "title",
content: [
<p>Text based on this footnote <span>1</span></p>,
<p>Another argument, here is my source <span>2</span></p>
]
}
];
return (
<div className="article-container">
<h3> {articles[i].title} </h3>
{ articles[i].content.map(paragraph => paragraph) }
</div>
);
}
Notice how I removed the string literal (``) and created an HTML element.
If the article content comes from an API call, then avoid using HTML tags inside strings. That's a bad practice actually. Always create the tags within the render() call and populate them with the API data you received.
Assuming the content array has to be supplied as raw HTML, a common solution is to use the dangerouslySetInnerHTML prop to render that HTML directly. You can introduce that to your <p> elements like this:
articles[i].content.map(paragraph => (
<p dangerouslySetInnerHTML={{ __html: paragraph }} />
))
A few other things to consider; I noticed a missing ) in your code after the <p> element of your map statement which will be causing a syntax error. Also, ensure that i is defined to an index in range of your articles array. Here's an example of each fix applied:
function ArticleItem() {
const articles = [
{
title: "title",
content: [
`Text based on this footnote <span>1</span>`,
`Another argument, here is my source <span>2</span>`
]
}
];
const i = 0;
return (
<div className="article-container">
<h3> {articles[i].title} </h3>
{
articles[i].content.map(paragraph =>
(<p dangerouslySetInnerHTML={{ __html: paragraph }} />)
)
}
</div>
);
}
Here's a working example as well - hope that helps!
Related
I have three strings and i want to concatenate them together, but one of them is within strong tag. The result is as below which is not as expected. What is the problem here?
Result:
There is no Colors for <strong>blah</strong> in the database.
Expected:
There is no Colors for blah in the database.
const fruitResult = 'There is no Colors for ';
const searchItem = `<strong>${fruitSearch}</strong>`;
const fruitResult1 = ' in the database.';
const fruitResult2 = 'No Data available.';
<div>
<h2>
{fruitSearch === ''
? `${fruitResult2}`
: `${fruitResult} ${searchItem} ${fruitResult1}`
}
</h2>
</div>
https://codesandbox.io/s/solitary-brook-q1rj93?file=/src/App.js
If you want to emit unescaped markup you can use dangerouslySetInnerHTML, but as it says on the tin you should only do this if you control and trust the source.
const html = `${fruitResult} ${searchItem} ${fruitResult1}`;
<div>
<h2 dangerouslySetInnerHTML={{ __html: html }} />
</div>
Here's a working fork of your sandbox demo.
I have a use-case where I need to format some text in React and also render HTML.
Here is an example of what I'm currently trying to achieve:
import React, {Fragment} from "react";
import {renderToString} from "react-dom/server";
function FormatText(props) {
const lines = props.children.split('\n');
return lines.map((line, index) => (
<Fragment key={index}>
{line}{index !== lines.length - 1 && <br/>}
</Fragment>
));
}
const content = {
first: 'This is some text\nwith new\n\nline characters - 1',
second: 'This is some text\nwith new\n\nline <strong>characters - <sup>2</sup></strong>',
};
function App() {
return (
<ol>
<li>
<FormatText>{content.first}</FormatText>
</li>
<li dangerouslySetInnerHTML={{
__html: renderToString(<FormatText>{content.second}</FormatText>)
}}/>
</ol>
)
}
As you can see, I have some content which contains \n characters and HTML. Calling the renderToString function converts the HTML into encoded characters, which means the HTML is not rendered properly.
Is there a way to render HTML inside a react fragment.
Ideally I wanted to do the following (but it doesn't):
function FormatText(props) {
const lines = props.children.split('\n');
return lines.map((line, index) => (
<Fragment key={index} dangerouslySetInnerHTML={{__html: renderToString(
<Fragment>
{line}{index !== lines.length - 1 && <br/>}
</Fragment>
)}}>
</Fragment>
));
}
<Fragment> doesn't adds any node to DOM and so you can't do dangerouslySetInnerHTML on it. It is basically a functionality provided by React to avoid addition of extra node to DOM when you needed to return more than one from return in render. So, if something doesn't exists on real DOM, you can't do anything on it.
renderToString is generally used on node server. When doing server side rendering, you want to send the html from server to client. So, better avoid renderToString also.
The issue is that, html doesn't recognises \n for new line etc. It needs html tags. The approach to use FormatText is fine or you can simply convert the \n to br and then use dangerouslySetInnerHTML inside the <li> tag.
const content = {
first: 'This is some text\nwith new\n\nline characters - 1',
second: 'This is some text\nwith new\n\nline <strong>characters - <sup>2</sup></strong>',
};
function App() {
return (
<ol>
<li dangerouslySetInnerHTML={{
__html: content.first.replace(/\n/g, "<br/>")
}}/>
<li dangerouslySetInnerHTML={{
__html: content.second.replace(/\n/g, "<br/>")
}}/>
</ol>
)
}
ReactDOM.render(<App/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Hope it helps. Revert for any doubts.
Hi I guess it is not possible, only way hot to pass formated html into DOm is via dom element DIV.
Maybe this link could help you or point to
https://reactjs.org/docs/dom-elements.html
I have encountered this problem while doing loop over array of objects. Consider I have below array of objects.
General : [
{
question: 'Whats you suggestion?',
answer: "Before you go ahead and book one of our trusted developer, please read our FAQ.",
},
{
question: 'Do you have guaranteed solution?',
answer: 'Please let us know at hello#stackoverflow.com.',
}
]
I am using map in my JSX (react application) something like this.
General.map((faq, index) => (
<details>
<summary>{faq.question}</summary>
<div>
<Linkify>{faq.answer}</Linkify>
</div>
</details>
))}
Now I want the text hello#stackoverflow.com to render as html anchor tag. I have done this through React Linkify. But how we can achieve this with pure javascript ?
This will work for emails, but you'll need to work out the regex for urls and chain them. Hope it helps.
General.map((faq, index) => {
const emailRegex = /([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/g;
const emailReplacer = "<a href='mailto:$1'>$1</a>";
return (
<details>
<summary>{faq.question}</summary>
<div>
<div>
{faq.answer.replace(emailRegex, emailReplacer)}
</div>
</div>
</details>
)
})
I am using react. I want to add a line break <br> between strings
'No results' and 'Please try another search term.'.
I have tried 'No results.<br>Please try another search term.'
but it does not work, I need to add the <br> in the html.
Any ideas how to solve it?
render() {
let data = this.props.data;
let isLoading = this.props.isLoading;
let isDataEmpty = Object.entries(data).length === 0;
let movieList = isLoading ? <Loader /> : isDataEmpty ? 'No results. Please try another search term.' :
Object.entries(data).map((movie, index) => <MovieTile key={index} {...movie[1]} />);
return (
<div className='movieList'>{movieList}</div>
);
}
You should use JSX instead of string:
<div>No results.<br />Please try another search term.</div>
Because each jsx should have 1 wrapper I added a <div> wrapper for the string.
Here it is in your code:
render() {
let data = this.props.data;
let isLoading = this.props.isLoading;
let isDataEmpty = Object.entries(data).length === 0;
let movieList = isLoading ? <Loader /> : isDataEmpty ? <div>No results.<br />Please try another search term.</div> :
Object.entries(data).map((movie, index) => <MovieTile key={index} {...movie[1]} />);
return (
<div className='movieList'>{movieList}</div>
);
}
You can use CSS white-space to solve the problem.
React Component
render() {
message = `No results. \n Please try another search term.`;
return (
<div className='new-line'>{message}</div>
);
}
CSS
.new-line {
white-space: pre-line;
}
OUTPUT
No results.
Please try another search term.
break text to line:
render() {
...
<div>
{this.props.data.split('\n').map( (it, i) => <div key={'x'+i}>{it}</div> )}
</div>
...
Some HTML elements such as <img> and <input> use only one tag. Such tags that belong to a single-tag element aren't an opening tag nor a closing tag. Those are self-closing tags.
In JSX, one has to include the slash. So, remove <br> and try <br />
Here is how I got around this. Let message be the prop/variable that has the string containing line breaks to be displayed in HTML as follows:
message = 'No results.<br>Please try another search term.';
<div>
{message}
</div>
To make this work, we need to use \n instead of break tag <br> and set the following css on the wrapper element of this message as follows:
message = 'No results.\nPlease try another search term.';
<div className="msg-wrapper">
{message}
</div>
CSS:
.msg-wrapper {
white-space: pre-wrap;
}
OUTPUT:
No results.
Please try another search term.
If you don't want put the string inside a <div> you could use <> to do it.
Like this:
var text = <>This is a text in the first line;<br />this is a text in a second line</>;
Just split text by /n, I do this in this way:
<div>
{text.split('\n').map((item, i) => <p key={i}>{item}</p>)}
</div>
Try with span
return (
<div className='movieList'><span>{movieList}</span></div>
);
If you are like in my situation and you don't want to add css, you can do that :
render () {
...
return (
...
<Typography component="p">
...
{(contact.lastname)?<div>Hello {contact.firstname} {contact.lastname}</div>:''}
...
</Typography>
...
);
}
using ` worked for me however i am not sure if it is the exact solution to the problem :
import React from 'react';
import ReactDOM from 'react-dom';
let element = (
<div>
<h1> Hello world</h1>
This is just a sentence <br></br>
But This line should not be in the same previous line. <br></br>
The above content proves its working. <br></br>
npm v6.14.6 | react : {React.version}
</div>
);
ReactDOM.render(element,document.getElementById("html-element-id"))
You can add a span tag and add block as a class.
Pomodoro Technique Timer <span className="block">with Bla</span>
The simplest thing which I did is by creating a component.
const EmptySpace = ({ spaceCount = 0 }) => {
return (
<>
{Array.from({ length: spaceCount }, (item, index) => {
return <br key={index} />;
})}
</>
);
};
export default EmptySpace;
<EmptySpace spaceCount={1} />
In your case you could do something like this:
const msg = (
<p>
No results <EmptySpace spaceCount={2} />
Please try another search term.
</p>
);
I am new to react (I am incorporating it into my ruby on rails project), here the component ive made:
<div id="articles"></div>
<script type="text/jsx">
var Article=React.createClass({
render: function(){
return(
<div>
{this.props.data}.map(function(item){
{item.name}
})
</div>
)
}
});
var input = [{name: "hello", email: "hello#example.com"}]
React.render(<Article data={input} />, document.getElementById("articles"))
When i run this, this is the error i get:
Uncaught Error: Parse Error: Line 7: Unexpected token .
{item.name}
I have set a prop to be an array. I just want to output the name hash key inside the array - why am i getting this error, it seems to me that this should work ?
You're not returning anything inside your map-statement, try writing
return {item.name};
However, I would suggest you try moving your map-function outside of the immediate render, its easier to read and less error-prone.
<div id="articles"></div>
<script type="text/jsx">
var Article=React.createClass({
render: function() {
var rows = this.props.data.map(function(item) {
//You could return any valid jsx here, like <span>{item.name}</span>
return item.name;
});
return(
<div>
{rows}
</div>
)
}
});
var input = [{name: "hello", email: "hello#example.com"}
React.render(<Article data={input} />, document.getElementById("articles"))
In JSX you have two 'modes'. JS mode (default) and JSX mode.
You enter JSX mode with a tag, like <div. In JSX mode only tags, attributes, and arbitrary text are allowed. You are also allowed to go into a JS mode with {}. This can happen any number of times.
function jsMode(){
<jsx>
{js(
moreJs,
<moreJsx>{evenMoreJs}</moreJsx>
)}
</jsx>;
}
So coming back to your code:
<div>
{this.props.data}.map(function(item){
{item.name}
})
</div>
Let's break this down into chunks
// js mode
<div> // begin jsx
{ // begin js
this.props.data // some js code
} // end js, back to jsx
.map(function(item) // this is just plain text visible to the user
{ // begin js
{item.name} // some invalid js, SyntaxError
} // end js
) // this is just plain text visible to the user
</div> // end jsx
// js mode
Because you want the .map to be interpreted as JS, and you were previously in JSX mode, it should also be in the {}s.
<div>
{this.props.data.map(function(item){
{item.name}
})}
</div>
Also, inside the .map callback, you're still in JS mode, so you need to remove the {}s
<div>
{this.props.data.map(function(item){
item.name
})}
</div>
And finally, you need to return the name from the .map callback.
<div>
{this.props.data.map(function(item){
return item.name;
})}
</div>
Other stuff
The code above will work, but probably not as expected.
If data was [{name: 'foo'}, {name: 'bar'}], map will return ['foo', 'bar'], and react will render it as:
<span>foo</span><span>bar</span>
To the user this appears as "foobar". If you want it to appear as two separate words you could put a space after each name:
<div>
{this.props.data.map(function(item){
return item.name + " ";
})}
</div>
Or return an element from .map and style it as you like. For example, an unordered list of names. Note that here we wrap item.name in {}s because we enter JSX mode.
<ul>
{this.props.data.map(function(item, i){
return <li key={i}>{item.name}</li>;
})}
</ul>
We also provide a key. In this case it's the index of the item, which works as long as the list never changes, or only has items added/removed to/from the end of the array.
Image credit: wikipedia/commons
If the array is reordered, or items are added/remove to/from the start or middle, we need a unique string identifier for each item.
If your data was [{name: "foo", id: "14019751"}, {name: "bar", id: "13409185"}], then:
<ul>
{this.props.data.map(function(item, i){
return <li key={item.id}>{item.name}</li>;
})}
</ul>