How to render React template in string as DOM using NextJS? - reactjs

I have some template which use React Component e.g:
<Section>
<div>
<HelloWorld />
</div>
<Hello name="my name" />
</Section>
and some components defined in my code such as :
export function Section({children}) {
return <div className="custom-class">{children}</div>
}
export function HelloWorld() {
return <div>Hello World</div>
}
export function Hello({name}) {
return <div>Hello {name}</div>
}
I would like to pass the template (as a string) to react and make it generate the correct DOM using the components I declared in my codebase. How can I do this ?
I tried using the props dangerouslySetInnerHTML but it only read raw html.
I also looked at next-mdx-remote https://github.com/hashicorp/next-mdx-remote which is almost what I need but for mdx.
Is there a straight solution or a library that exist who solve this issue ?

Related

React JSX to string

How can I convert the children of a React component to a string without it rendering?
import { renderToString } from 'react-dom/server';
const MyComponent = () => {
return (
<h1>Hello</h1>
)
}
const Output = () => {
return (
<pre>
{renderToString(
<div>
<MyComponent />
<MyComponent />
<MyComponent />
</div>
}
</pre>
)
}
How can I make the above show:
<div>
<MyComponent />
<MyComponent />
<MyComponent />
</div>
instead of
<div>
<h1>Hello</h1>
<h1>Hello</h1>
<h1>Hello</h1>
</div>
Ultimately I'm looking to show how the code for the component is written in a ui system. Trying to parse the children instead of writing the component twice. Any examples of open source websites demonstration ui components with a code block works too, and I'll just look into that.
Take a look at react-code-blocks. Basically you can add any code, just like Stackoverflow.

React tailwind, cannot pass tailwind css from parent to child

I am running into a simple issue that doesn't seem to have an answer on quick google search or Tailwind doc.
I am a Vuejs user but I have started learning React. I have opted to use TailwindCSS for testing my React application but I noticed there is some differences of Tailwind usage between Vuejs and React.
In Vue, I can control a child component via the parent component like so:
Parent component:
<template>
<div class="w-screen">
<ChildComponent class="w-1/2 mx-auto" />
</div>
</template>
With the child being able to centre on screen through the above parent component as should in the ChildComponent's class.
However, when I tried to do the same in React like so:
Parent component:
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
Nothin happens when I placed the CSS at the Homepage child component from the parent.
I am sure there is a simple answer but I wasn't about to search the doc or use any keywords to find this problem. Anyone got a hint or confirm this is intended in React or have I done something wrong with the installation?
This is less of a Tailwind question and more of a React question. You cannot use className on the Homepage component without passing it as a prop. In your case, Homepage is not expecting any className. So while making your Homepage component you have to provide a prop called 'className' then it will work fine.
Or if you simply use a div in place of Homepage it will work normally. Have a look at this codesandbox link
You need to consider that <Homepage/> is a React component and cannot accept HTMLAttrs just like that.
this example might clear it:
const app = () => {
<div className="bg-black">
<Homepage className="bg-red" />
</div>
}
const homePage = (props) => {
<div className={props.className}>
<h1 className="bg-red">hi</h1>
</div>
}
the className that you pass to <Homepage/> is actually a props rather than Html attribure.
In Vue it's fairly straightforward but in react you need to be explicit and use className in your component
// Creating component
const Button = ({ className, children }) => {
return <button className={`${className} bg-red-500`}>{children}</button>
}
export default Button
// Using component
<Button className="text-white">MyButton</Button>
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
views/Homepage
you have to receive props that are going to be passed as className
const homePage = ({className}) => {
<div className={className}>
<h1 className="bg-red">hi</h1>
</div>
}
export default homePage
then export your component

Why Won't This Render as JSX?

I have a string variable, with this HTML code like so:
this.state.contents:
<p>This Handbook is designed to provide you with information about your employment at {this.props.clientName} and its affiliates and subsidiaries (referred to throughout this Handbook as “{this.props.clientName}” or the “Company”).</p>
I pass it to a child component like this:
<Policy key={filteredPolicy.id} id={filteredPolicy.id} contents={filteredPolicy.contents} clientName={this.state.client}/>
The child component is this:
<Card.Body className="content" >{this.props.contents}</Card.Body>
But in the component, it renders as the string and just shows all the HTML tags. How do I get it to actually render correctly as HTML code? A second issue is the variables of {this.props.clientName} also do not show up... it just literally renders {this.props.clientName} as a string. It all works correctly if I just do it as HTML. But when I try to do it this way, no dice.
While you can still use dangerouslySetInnerHTML to achieve it like this, it's not recommended
function Child({ data }) {
return <div dangerouslySetInnerHTML={{__html: data}}></div>;
}
const test = "test-data";
export default function App() {
const [data] = useState(`<div>${test}</div>`); // note the ${} (template literal) here instead of {}, because this is a string, not React component
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child data={data} />
</div>
);
}
Live example
Define a renderData function inside Parent component to render your html, pass it to Child as a prop, and call that renderData function here. You can use your state, props inside that renderData function as you want.
So the above example can be rewrite like this
function Child({ renderData }) {
return <div>{renderData()}</div>;
}
const test = "test-data";
export default function App() {
const renderData = () => {
return (
<div>{test}</div>
)
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child renderData={renderData} />
</div>
);
}
Live example

How can i pass a pirce of HTML content into a stateless react component?

I want to make a simple React component that wraps the given HTML content into a tag that serves as a context in which the content is displayed.
function Content(content) {
return <div>{content}</div>;
}
<Content>
<span>Hey!</span>
</Content>
What am i doing wrong?
function Content(props) {
return <div>{props.children}</div>;
}
Using ES6 syntax:
const Content = ({ children }) => <div>{children}</div>
Simple React component that wraps the given HTML content.
var content = "<Content><span>Hey!</span></Content>"
function Content() {
return (
<div className="content" dangerouslySetInnerHTML={{__html:
content}}>
</div>
);
}

How to use external templates for ReactJS?

I am learning ReactJS and in ALL examples that I see on the web the HTML code is always rendered inline, meaning that you have to add all HTML markup directly into the JS file which is super ugly and very hard to work with (if you have a lot of markup). Isn´t there a way to put all HTML in a separate file just referens that file when rendering? Like we do in Rails or Angular 2.
This is my code:
var Main = React.createClass({
render() {
return (
<div> <h1>Hello, World!</h1> </div>
)
}
});
I want to put this in a separate file:
<div> <h1>Hello, World!</h1> </div>
You can put your html in a separate .js file and import it in your component then use,
htmlMarkup.js
module.exports = `<div> <h1>Hello, World!</h1> </div>`;
and then in your component
render() {
return (<div dangerouslySetInnerHTML={require('path/to/htmlMarkup.js')} />)
}
if you want to set some property in your html file, then you can export a function instead of string.
module.exports = (message) => `<div> <h1>${message}</h1> </div>`;
and then in render method.
render() {
return (<div dangerouslySetInnerHTML={require('path/to/htmlMarkup.js')('Hello World')} />)
}

Resources