Prarse String to Html and Components - reactjs

I am building a website with Nextjs and have my course lessons stored in a different file. In there I have String containing content like for example
taskInfo: `
<h1 className="task-section__info-header px-task pt-task-header">Hello World!</h1>
<div className="task-section__info-description px-task">
For this lesson, we will be creating a simple "Hello World!" program.
<br />
If you forgot how to do this, revisit the previous lesson.
<div className="task-section__code">
<CodeSnippet
language="javascript"
>
console.log("Hello World!");
</CodeSnippet>
</div>
`,
My goal now is to pass this string as a prop to a component and display that string on the screen with the components and the rendered HTML. I've tried things like html-to-react or unified or babel, but they all provided their own errors and didn't work. Html-To-React, for example, only converts the HTML but not the component.

Related

Issues using react-loading-overlay

I have a simple react app, and im trying to add a simple loading overlay.
I saw the most common usage is react-loading-overlay.
My main app.js structure looks like that, I have a simple menu and a deck.gl map
<div className="container">
<AppMenu/>
<div className="deckgl_map">
<DeckMap/>
</div>
</div>
If I get it correctly, to use the loading overlay, I need to do something like that (using true for testing):
<LoadingOverlay
active={isActive}
spinner
text='Loading your content...'
>
<div className="container">
<AppMenu/>
<div className="deckgl_map">
<DeckMap/>
</div>
</div>
</LoadingOverlay>
But once I do that, my entire app page, instead of filling the whole screen, just takes the top 20% of the screen (and the rest is empty white).
Why wrapping my component with the LoadOverlay component causes the whole page to look weird?
Do I need to "play" with the CSS for the LoadOverlay component?

How can I inject arbitrary string HTML content into the head of my gatsbyjs site?

I have a GatsbyJS site that I am working on where the main content source is a Wordpress install. One of the things I like to add to my sites is the ability to have placeholder areas in the site where I can control the content via the CMS. Usually I have a header_scripts area that goes at the bottom of the <head> tag, a body_scripts area that goes at the start of the <body> tag, and a footer_scripts area that goes at the bottom of the page <body>. With these three, I can usually integrate third-party add-ins pretty easily without having to do code deployments.
Sometimes I need to embed stylesheets, sometimes I need to embed script tags, and sometimes I need to throw in <meta> tags. Really the content could be anything. This data comes back as a raw string from my Wordpress GraphQL endpoint.
So now my question is, how do I get this content injected into my Gatsby site in the following places:
<html>
<head>
...
{header_scripts}
</head>
<body>
{body_scripts}
...
{footer_scripts}
</body>
</html>
I've found so far that I can just include the body_scripts and footer_scripts in a fairly regular manner in my Gatsby page template. In gatsby-node.js, I pass in the property values using the pageContext. It's kind of a bummer that they need to be wrapped in a <div /> tag, but they seem to work just fine.
import React from 'react'
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
Now for the real question. I am stumped on how to get the dynamic content from the header_scripts into the Gatsby server-side-rendering <head> tag. The closest thing I have found to being able to inject content into the head is to leverage the gatsby-ssr.js onRenderBody function. However, this seems to require pre-determined React component instances in order to function. I can't just pass it in plain raw string content and see the output in the page source:
export const onRenderBody = async ({
pathname,
setHeadComponents,
setHtmlAttributes,
setBodyAttributes,
setPreBodyComponents,
setPostBodyComponents,
setBodyProps
}, pluginOptions) => {
setHeadComponents(['<script>alert("hello");</script>'])
}
This results in an escaped string getting inserted into the <head> tag:
<html>
<head>
...
<script>alert("hello");</script>
</head>
<body>
...
</body>
</html>
I'm at a loss as to how to proceed. I can't just wrap my string in a <div /> tag like in the body because div tags can't go inside the head tag. I can't think of any head-capable HTML tags that would accept this kind of content.
The only idea I've had is to actually parse the string content into full React components. This seems daunting given the number of possible tags & formatting that I would need to support.
Am I going about this the wrong way? How can I get my arbitrary content into my Gatsby site's head tag?
It's a broad question and it will need some trials and errors to ensure that it's fully working without caveats in all scenarios but, among the things you've tried, you can add a few more options to the list to check which ones fit better.
Regarding the body_scripts and footer_scripts both can be inserted using the:
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
In any desired page or template. For the header_scripts and the meta tags (SEO), you can use the <Helmet> component. Basically, using this component, everything that is wrapped inside, it's becomes transpiled inside the <head> tag once compiled.
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
<Helmet>
{this.props.pageContext.headerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.headScripts}} />
)}
</Helmet>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
However, if the data comes from a CMS, it won't be available in the SSR yet, so, one easy thing you can do is to customize the outputted HTML (html.js) that Gatsby generates in each compilation. From the docs:
Customizing html.js is a workaround solution for when the use of the
appropriate APIs is not available in gatsby-ssr.js. Consider using
onRenderBody or onPreRenderHTML instead of the method above. As a
further consideration, customizing html.js is not supported within a
Gatsby Theme. Use the API methods mentioned instead.
Run:
cp .cache/default-html.js src/html.js
Or manually, copy the .cache/default-html.js file and paste it /src folder. There you can customize the final HTML.

Is it good practice to create a React component just to hold props?

Is it considered a good idea to simply have a Component in React that renders nothing and performs no logic, but rather just behaves as a "container" for its props?
The main reason I bring this up is for organizational purposes. Instead of using a <div> element, I thought it would be better to give it a more meaningful name. In my particular case, I'm trying to create a Tabs component, which is designed to render Tabs and their respective contents.
The Tabs component is going to extract out the data and render it properly. As you can see in the example below, The <TabItem> component really does nothing and is simply a <div> element that has been renamed.
<TabContainer>
<TabItem label="firstTab">
<h1> Hello </h1>
</TabItem>
<TabItem label="secondTab">
<h1> Hello </h1>
</TabItem>
</TabContainer>
If I were to use div's instead, it would look like:
<TabContainer>
<div label="firstTab">
<h1> Hello </h1>
</div>
<div label="secondTab">
<h1> Hello </h1>
</div>
</TabContainer>

React Js component or way to display both html and emoj

I want to display text which can contain with emoj and html . I`ve already using react-emoji-render component. But it's not supporting HTML .
Example text I want to display:
<h1>Hello</h1> :)
Will this help (instead of using react-emoji-render)?:
1. Include <link href="https://afeld.github.io/emoji-css/emoji.css" rel="stylesheet"> to html template.
2. Use it: <h1>Hello world! <i class="em-svg em-100"></i></h1>
Library

Props vs Children to pass HTML content in ReactJS

I need create a component to render like this:
<div class="row">
<div class="col">
<div class="some another class">
<h3>{{title}}</title>
</div>
</div>
<div class="col">
<p>{{contentA}}</p>
</div>
<div class="row">
<div class="some wrapper">
<p>{{contentB}}</p>
<div>
</div>
<div>
It will receive the following data:
title - a string
contentA - a large string (paragraph), may contain
links (a href)
contentB - a large string or a complex HTML code
Here are the following methods I found. However, I'm not sure about which one is the recommended way by React.
Method 1
<Component title="a" contentA="some large content" contentB="another large content"/>
Pros: Easy to access different props in different sections of the component
Cons: Too complex to handle if the content as large HTML content
Method 2
<Component>
<title>a</title
<content>some large content</content>
<content>another large content</content>
</Component>
Pros: Much simpler code
Cons: Need to filter props.children and find each element to put in correct place in the component
This is not really an accurate statement:
Cons: Too complex to handle if the content as HTML contents
If a value can be held in a variable as a string, it can be used as an argument passed into your component. If you don't want to be bothered trying to escape the quotes inside your prop values, I would encourage you to ditch the <Component attr="someValue"/> syntax and instead use <Component attr={'someValue'}/>. This allows you to pass variables into your props. This also allows you to use template literals to pass values, like so:
<Component
title="a"
contentA={`
<html>
<head></head>
<body>
<p>Here is my super-big</p>
<p>HTML-infused content</p>
<p>I can even inject ${variables} in here!</p>
</body>
</html>
`}
contentB="another large content"
/>
If you feel like that starts to clutter-up the declaration of your component, you can instead set those values in a variable and then pass them very cleanly into the component, as such:
render() {
const bigHtmlContent = (
<html>
<head></head>
<body>
<p>Here is my super-big</p>
<p>HTML-infused content</p>
<p>I can even inject {variables} in here!</p>
</body>
</html>
);
return (
<Component
title="a"
contentA={bigHtmlContent}
contentB="another large content"
/>
);
}
Of course, you can move the definition out of the render() function altogether if that suits you better:
getBigHtmlContent() {
return (
<html>
<head></head>
<body>
<p>Here is my super-big</p>
<p>HTML-infused content</p>
<p>I can even inject {variables} in here!</p>
</body>
</html>
);
}
render() {
return (
<Component
title="a"
contentA={() => this.getBigHtmlContent()}
contentB="another large content"
/>
);
}
When I'm creating components, I tend to pass everything as props (as shown in the examples above). I only use children if I'm creating a higher-order component which, by design, is supposed to act as a container for certain types of children.
For example, in Material UI there is a <List> component which requires one-or-more <ListItem>s. In that case, I don't think it would make much sense to pass the <ListItems>s as props. They are (and should be) children of the <List> component.
React is all about creating granular components, the more granular you component tree is, you are doing it the more React way.
You say you get 3 things text,contentA and ContentB
Title: it's already granular.
content A: You say its a "a large string (paragraph), may container links (a href)"
, if its a paragraph it is granular but if its a collection of paragraphs, I think you should take that to a different component. Ex: ContentA component
Content B: This is clearly said that its a complex HTML code, that is what is React for, you need to break this complex HTML code into granular components which will make it more maintainable and it is a React best practice too.
have patience while breaking this into components, it's definitely worth it.
hope that helps.

Resources