How to render string including JSX component with PascalCase in React? - javascript

I have a React app, receiving the blog post data from external cms. The data is raw HTML as a string, like this:
<h1>hello</h1>
<img src="example.com/felan.jpg">
<p>some text</p>
<img src"example.com/another.jpg">
...
Now, I want to replace img HTML tag with a jsx component called Img (with capital I).
I do it with:
let postContentOptimized = post.replace("img", "Img");
<article dangerouslySetInnerHTML={{ __html: postContentOptimized }} />
But it automatically converts Img to img (changes PascalCase).
I also tried with other component names, and it throws this error:
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.

I found a package called react-jsx-parser.
Its documentation isn't straightforward, thus I skipped it the first time I found it.
Here's how to do it if you're confused like me:
<JsxParser components={{ components used in your string }} jsx={the string you want to parse} />
example:
<JsxParser components={{ Img }} jsx="<Img src="hello.png /><p>hello</p>" />

Related

How to set innerHTML react js format

So I given this code:
render() {
console.log(this.props, 'ey');
const var1 = "<div className={{blahblah}} style={{width: '10px'}}>{textvar}</div>"
return (
<div dangerouslySetInnerHTML={{ __html: `${var1}` }}>
</div>
);
}
Of course that's just an example, but the var1 should be a big chunk of html file in jsx format, however doing that one renders them as they are and doesn't convert them to regular html.
I also tried setting innerHTML via refs on componentDidMount but same problem happens.
this is what it should look like when it renders:
<div class="blahblah style="width: 10px"}}>the variable text</div>
Any help would greatly appreciated. thanks!
You need to do this to use ES6 interpolated string literals (inaccurately called template literals by the spec):
<div dangerouslySetInnerHTML={{ __html: ${var1} }}>
But this would be simpler:
<div dangerouslySetInnerHTML={{ __html: var1 }}>
However, in your string for the inner html, you may want to use an interpolated string literal if what you want is to use the values of the blahblah and textvar variables.
Note you need to use class instead of className since React will just set the inner html rather than treat it as JSX and className is only for JSX.
const var1 = <div class=${blahblah}>${textvar}</div>;
If you are using a class, no need to also use the style keyword. Just set the width in your CSS.
You can see a working example of the above on CodePen.

adding images to in react with dynamic links

I have created react app using create-react-app , there is a component which need to be reused multiple times, this component contain <img> tag, image is different for each instance of the component.
I am passing image path as imagePath prop from parent to child component and then that child need to load image from that path.
i can not use
import image from imagePath
because i don't know the path until component is build, and import statement don't work within component body.
I tried doing<img src={imagePath}>
that also don't work, can you point me to right direction?
adding code for further clarification
first approach it doesnt work. content is object passed by parent and content.image have value of ./images/keeper.PNG
import React from 'react';
import image from './images/keeper.PNG'
export default function Project(props)
{
return <div className='projectContainer' >
<div className='projectImage'>
<img src={props.content.image}
alt ='' />
</div>
<div className='.projectDescription'>
<h4>{props.content.name}</h4>
<p>{props.content.intro}</p>
<h5>Technologies and problems</h5>
<p>{props.content.tech}
</p>
</div>
</div> }
second methond <img src={image} alt ='' /> it works fine and show image but as stated above i don't know image path before the component is created
Sample
Parent component
let image = 'https://www.belightsoft.com/products/imagetricks/img/intro-video-poster#2x.jpg'
function Parent(){
return <Child image={image}/>
}
Child component
function Child(props){
return <img src={props.image} alt="icon-image" />
}
or
directly if you import in component
import imagePath from './image.jpg';
function Child(props){
return <img src={imagePath} alt="icon-image" />
}
Try using it this way, where you can pass the imagePath via props
<img src={require(`${props.imagePath}`)} />
This alone will do the job.
When using Webpack you need to require images in order for Webpack to
process them, which would explain why external images load while
internal do not, so instead of img src= {"/imagePath"} you need to
use img src= {require('/imagePath')} replacing imagePath with the
correct image name for each of them. That way Webpack is able to
process and replace the source img.

Global JS variable to pass HTML chunk to React component

I have a piece of HTML I need to send to a React component on page load without rendering it. I'd rather not us AJAX due to cache, but I may revert to that if I can't figure this out.
On the jsp side, I have this:
<script>window.banner_data_for_desktop = "...droplet..."</script>
This contains the HTML chunk I need to pass
<div id="desktop-top-banner">
<div>
...
</div>
</div>
On the jsx side, I've tried rendering directly like this:
<div id="top_bar">{window.banner_data_for_desktop}</div>
This renders the content, but displays the div tags as a string and not output as HTML.
So then I tried using dangerouslySetInnerHTML like this:
<div id="top_bar">dangerouslySetInnerHTML={{ __html: window.banner_data_for_desktop }}</div>
This results in an error:
Invariant Violation: Objects are not valid as a React child (found: object with keys {__html}). If you meant to render a collection of children, use an array instead.
I've tried using Stringify, toString, creating a function to return the html like this:
function createMarkup() {
return {__html: window.banner_data_for_desktop};
}
All without any luck. If any one has a suggestion to render HTML from the global JS object, I would greatly appreciate it!
dangerouslySetInnerHtml should be an attribute of the tag:
<div dangerouslySetInnerHTML={{__html: "HTML CHUNK"}}></div>

<div> cannot appear as a descendant of <p>

I'm seeing this. It's not a mystery what it is complaining about:
Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>. See ... SomeComponent > p > ... > SomeOtherComponent > ReactTooltip > div.
I'm the author of SomeComponent and SomeOtherComponent. But the latter is using an external dependency (ReactTooltip from react-tooltip). It's probably not essential that this is an external dependency, but it lets me try the argument here that it is "some code that's out of my control".
How worried should I be about this warning, given that the nested component is working just fine (seemingly)? And how would I go about changing this anyway (provided I don't want to re-implement an external dependency)? Is there maybe a better design that I'm yet unaware of?
For completeness sake, here's the implementation of SomeOtherComponent. It just renders this.props.value, and when hovered: a tooltip that says "Some tooltip message":
class SomeOtherComponent extends React.Component {
constructor(props) {
super(props)
}
render() {
const {value, ...rest} = this.props;
return <span className="some-other-component">
<a href="#" data-tip="Some tooltip message" {...rest}>{value}</a>
<ReactTooltip />
</span>
}
}
Thank you.
If this error occurs while using Material UI <Typography> https://material-ui.com/api/typography/, then you can easily change the <p> to a <span> by changing the value of the component attribute of the <Typography> element :
<Typography component={'span'} variant={'body2'}>
According to the typography docs:
component : The component used for the root node. Either a string to use a DOM element or a component. By default, it maps the variant to a good default headline component.
So Typography is picking <p> as a sensible default, which you can change. May come with side effects ... worked for me.
Based on the warning message, the component ReactTooltip renders an HTML that might look like this:
<p>
<div>...</div>
</p>
According to this document, a <p></p> tag can only contain inline elements. That means putting a <div></div> tag inside it should be improper, since the div tag is a block element. Improper nesting might cause glitches like rendering extra tags, which can affect your javascript and css.
If you want to get rid of this warning, you might want to customize the ReactTooltip component, or wait for the creator to fix this warning.
If you're looking for where this is happening, in console you can use: document.querySelectorAll(" p * div ")
I got this warning by using Material UI components, then I test the component="div" as prop to the below code and everything became correct:
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
<Typography component="span">
<Grid component="span">
Lorem Ipsum
</Grid>
</Typography>
Actually, this warning happens because in the Material UI the default HTML tag of Grid component is div tag and the default Typography HTML tag is p tag, So now the warning happens,
Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>
Details (and some HTML theory regarding the warning) : The <div> cannot appear as a descendant of <p> message is shown due to the fact that the permitted content of a <p> tag is according to the standards set to the Phrasing Context which does not include <div> tags. See the links for more details.
Your component might be rendered inside another component (such as a <Typography> ... </Typography>). Therefore, it will load your component inside a <p> .. </p> which is not allowed.
Fix:
Remove <Typography>...</Typography> because this is only used for plain text inside a <p>...</p> or any other text element such as headings.
This is a constraint of browsers. You should use div or article or something like that in the render method of App because that way you can put whatever you like inside it. Paragraph tags are limited to only containing a limited set of tags (mostly tags for formatting text. You cannot have a div inside a paragraph
<p><div></div></p>
is not valid HTML. Per the tag omission rules listed in the spec, the <p> tag is automatically closed by the <div> tag, which leaves the </p> tag without a matching <p>. The browser is well within its rights to attempt to correct it by adding an open <p> tag after the <div>:
<p></p><div></div><p></p>
You can't put a <div> inside a <p> and get consistent results from various browsers. Provide the browsers with valid HTML and they will behave better.
You can put <div> inside a <div> though so if you replace your <p> with <div class="p"> and style it appropriately, you can get what you want.
Details (and some HTML theory regarding the warning) : The <div> cannot appear as a descendant of <p> message is shown due to the fact that the permitted content of a <p> tag is according to the standards set to the Phrasing Context which does not include <div> tags. See the links for more details.
The warning appears only because the demo code has:
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}> // <==NOTE P TAG HERE
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
Changing it like this takes care of it:
function TabPanel(props) {
const {children, value, index, classes, ...other} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Container>
<Box> // <== P TAG REMOVED
{children}
</Box>
</Container>
)}
</div>
);
}
I got this from using a react-boostrap <Card.Text> section of a component in React. None of my components were in p tags. <Card.Text> by default shows up as a in the HTML tree once rendered and basically having a custom React component returning its jsx elements within a <div> it causes a <p><div>...</div></p> which is a bad HTML. So to fix this issue if one is using <Card.Text> you can basically use the 'as' attribute as the following
<Card.Text as='div'> and this will resolve the warning because it allow a tree such as <div><div></div></div>
With Material UI !!!!!
I've spent an embarassing amount of time but thanks to this answer --> here by Alex C which gave this very simple yet smart solution
document.querySelectorAll(" p * div ")
So at my surprise , was the Material UI DialogContentText component DialogContentText API that caused the issue
So just use component={'span'} to fix the problem (it won't effect the style)
<DialogContentText id="alert-dialog-inputs" component={'span'}/>
I had a similar issue and wrapped the component in "div" instead of "p" and the error went away.
I got this from using a custom component inside a <Card.Text> section of a <Card> component in React. None of my components were in p tags
If you are using ReactTooltip, to make the warning disappear, you can now add a wrapper prop with a value of span, like this:
<ReactTooltip wrapper="span" />
Since the span is an inline element, it should no longer complain.
There is a problem in App.js during its rendering.
Don't use <div>...</div> to render just use <>...</>.
I had same issue with react-bootstrap and with Alex C's solution i found that i use <div> in <Card.Text> which is kinda <p>
<Card.Text>
<div>{name}</div>
<div>{address}</div>
<div>{size}</div>
</Card.Text>
I got this error when using Chakra UI in React when doing inline styling for some text. The correct way to do the inline styling was using the span element, as others also said for other styling frameworks. The correct code:
<Text as="span" fontWeight="bold">
Bold text
<Text display="inline" fontWeight="normal">normal inline text</Text>
</Text>
If you couldn't solve problem use bottom method
You have this problem because, you Open Grid tag or div in text tag and It can be false.
For example I write part of the code That have problem.look at it:
<Typography>
text
<Grid>
</Grid>
</Typography>
Be careful I open Grid tag in Typography tag. So It is false if we Open Grid tag in typography tag.
As far as my knowledge know when We open in typograghy tag, We are Deviating from the MUI standard.
So for best way you can us this Code:
<Grid>
<Typography>
text
</Typography>
</Grid>
If you used this code, you would not Any problem.
As result if you have problem again
You have to check components and
See in which component you did not Choose the correct mode.
You should check:
Span typography h1 h2 h3 h4 h5 h6 p
I hope I helped you .
I resolved that issue by removing my tag that I used to wrap around my 2 textfields that were causing that same error log.
You can not descendant of ;
Error: <p><div>aaaa</div></p>
Solution <div><p>aaaa</p></div>
(Extra)
Problem can be <p> elements inside <p> element in other similar errors.
Error:
<p>
<p>
</p>
</p>

How to render HTML Template and bind data from JSON response in ReactJS?

I have to render an HTML template using reactjs. HTML template is dynamic and get through an API call. There is provision in template to bind the data in html.
Sample HTML template is as follows,
<a target="_blank" href="{ad.url}">
<div class="ads temp-1">
<h2>{ad.name}</h2>
<div class="adv-content">
<div class="advs-image">
<img src="{ad.image}" />
</div>
<div class="adv-desc">{ad.description}</div>
</div>
</div>
</a>
Here ad is an Object which contains the properties url, image, name, description etc
Sample ad Object is as follows,
var ad = {
"image": "testimage.jpg",
"url": "http: //google.com",
"name": "testadvertisement",
"description": "testdescription"
}
I have achieved this in AngularJs using, $compile service.
Now I want to move this to reactjs.
I have tried to render using reactjs render function, But it didn't help. It renders html as string.
Is there any compile like function in reactjs ? Or could you please suggest any other way to do this right way ?
Any help appreciated.
As I correctly undestand you should use dangerouslySetInnerHTML prop.
For example:
// SomeComponent.js
// other methods...
render() {
// `htmlFromResponse` is your plain html string from response.
return (
<div dangerouslySetInnerHTML={{ __html: htmlFromResponse }} />
);
}
Using this prop, you can render plain html string into div element.
If you are getting html template from server, and want to pass variable to it before rendering, you can do it with Mustache package:
import Mustache from 'mustache';
// template should contain variables in {{ ... }}
const html = Mustache.render(htmlFromServer, {
variable: 'value'
});
Next, you can render output html using dangerouslySetInnerHTML prop.
create a react component which renders the HTML data, then pass your Json data as Prop to the component. this will give React element access to data and Rendered HTML will be automatically updated when Json data changes.
Check out some react tutorial video over youtube, that will give you an overview of how ReactJs works
here is how to Pass Props
https://jsfiddle.net/abhirathore2006/6a403kap/
var Hello = React.createClass({
render: function() {
console.log(this.props)
return <div>Hello {this.props.name}
<h5>{this.props.d1.name}</h5>
id:{this.props.d1.id}
</div>;
}
});
ReactDOM.render(
<Hello name="World" d1={{"name":"test","id":"5"}} />,
document.getElementById('container')
);

Categories