How to display the html of the children slot? - reactjs

I've got this react component where I'm passing in a title and the children is a simple div with the word test.
export default function Home() {
return (
<div>
<main>
<SourceCode title="Header">
<div>test</div>
</SourceCode>
</main>
</div>
);
}
I want to display the HTML of whatever is in the children slot so in this example I want to to show <div>test</div>, I've tried using pre but I get the error TypeError: Converting circular structure to JSON
export default function SourceCode({ children, title }) {
return (
<div>
<div>{title}</div>
<div>{children}</div> // <== Here I want to render the markup, this works
<div>
<pre>{JSON.stringify(children)}</pre> // <== Here I want to show the markup
</div>
</div>
);
}
I have also tried
<pre>
<code>{children}</code>
</pre>
but this just shows test and I want it to show <div>test</div>

You could try with ReactDOMServer.renderToStaticMarkup
import ReactDOMServer from 'react-dom/server';
export default function SourceCode({ children, title }) {
const markup = ReactDOMServer.renderToStaticMarkup(children);
return (
<div>
<div>{title}</div>
<div>{children}</div> // <== Here I want to render the markup, this works
<div>
<pre>{markup}</pre> // <== Here I want to show the markup
</div>
</div>
);
}

Related

How to modify this to not be two components in React

NOTE: I HAVE REPLACED THIS QUESTION WITH ONE WITH MORE CLARITY AT THE LOCATION: Context not returned when referencing React component as function instead of JSX
I WOULD LIKE TO DELETE THIS BUT SO WILL NOT LET ME.
I have the following JavaScript file that is one React component calling another one nested inside it. I want to change this to not use the name of the nested component but instead create the internal component as an anonymous one.
I want to usr the JavaScript name and not return JSX.
Here is my original working component
const InsideComponent = () => {
return (
<div>
Inside Component
</div>
);
};
export default function Speakers() {
return (
<div>
<InsideComponent />
</div>
);
}
I've tried a few combinations including this below that do not work
export default function Speakers() {
return (
<div>
{
return (
{ InsideComponent()}
)
}
</div>
);
}
Using { inside the context of JSX stops the JSX syntax and begins a plain JavaScript expression. (Not a function - no return.) So from here
<div>
{
for the syntax to be valid, you'd need to have an expression that evaluates to a JSX element:
export default function Speakers() {
return (
<div>
{
(
<div>
Inside Component
</div>
)
}
</div>
);
}
But the nesting of a JavaScript expression isn't useful at all there - better to just insert the plain JSX instead.
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
When you want to merge components, you just need to merge the JSX portion of it.
In your example, you can just do
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
Why not this?
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
Unless you're using the InsideComponent as part of other components, there is no need to separate the two. But if you want to, just use it like you would any other component.
export default function Speakers() {
return (
<div>
<div>
<InsideComponent />
</div>
</div>
);
}
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
Is this is what you are looking for?

Div content is mapping different components

I want to ask how could I implement in reactjs the next thing.
Imagine a page with 2 buttons and a div. When I press one button the content of the div would be a list of components mapped. When I press the other button the div content would be another list of components ( different component type as well ).
So more or less, the effect that results from this is a menu inside a page that loads different things in a div.
I am also willing to hear other options of implementing this, but mostly i'm here to ask you for a short example of how could I implement this thing.
import { useState } from "react";
import "./styles.css";
const Component1 = () =>{
return(
<div>
<h1>Component 1</h1>
</div>
)
}
const Component2 = () =>{
return(
<div>
<h1>Component 2</h1>
</div>
)
}
export default function App() {
const [component, setComponent] = useState("COMPONENT_1");
const renderComponent = () =>{
switch(component){
case "COMPONENT_1":
return <Component1/>
case "COMPONENT_2":
return <Component2/>
default:
return <div/>
}
}
return (
<div className="App">
<div>
{renderComponent()}
</div>
<button onClick={()=>setComponent("COMPONENT_1")}>Render component 1</button>
<button onClick={()=>setComponent("COMPONENT_2")}>Render component 2</button>
</div>
);
}
you can replace Component1 and Component2 with whatever you want.
Or
You can use a library like React Router https://reactrouter.com/
let me know if there is anything else you want me to add.

Pass a function within component returning specify content

I have multiple pages in my site.
I created a component for content section containing text and images. For each page, I have created a class to show/hide on the corresponding page. Now the problem is that the page loading is very slow due to large contents. Is there any way to load only the content required for the page. I don't wish to hide/show because that is still rendered in the DOM making the site slow.
something like below
//in page1.js
<ContentComponent content="page1"/>
//in page2.js
<ContentComponent content="page2"/>
//component
const ContentComponent =() => {
return(
page1= {
<div>content for page 1</div>
}
page2= {
<div>content for page 2</div>
}
)
}
Is there a way to do something like this ?
Probably you want to do:
// ContentComponent.jsx
const ContentComponent =(props) => {
if (!props.children) {
return null;
}
return <div style={/* some styles for content */}>{props.children}<div>;
}
// page1.jsx
...
return (
<div>
<h1>Page 1</h1>
<ContentComponent>
<div>content for page 1</div>
</ContentComponent>
</div>
);
// page2.jsx
...
return (
<div>
<h1>Page 2</h1>
<ContentComponent>
<div>content for page 2</div>
</ContentComponent>
</div>
);
You can access through props- like this using destructuring.
//in page1.js
<ContentComponent content1="page1"/>
//in page2.js
<ContentComponent content2="page2"/>
//component
const ContentComponent =({content1, content2}) => {
return(
<>
<h3>{content1}</h3>
<h3>{content2}</h3>
</>
)
}

Load a Popup Component

I am trying to display a detail component in a popup window. My App.js component contains a List component with list of Item component. When click Item component, I want to show a Detail popup. The togglePopup() function is passed from parent List component to child Item then to Detail. Right now, the popup does not show up. Below is my code:
App.js
class App extends Component {
state={ showPopup: false,
selectedItem:'',
Items:[]};
togglePopup=()=> {
this.setState({
showPopup: !this.state.showPopup
});
}
onItemseSelect=(item)=>{
this.setState({selectedItem:item});
};
render(){
const Items=['aa','bb','cc'];
return(
<List
Items={this.state.Items}
onItemSelect={this.onItemSelect}
onClick={this.togglePopup}
/>
{this.state.showPopup ?
<Detail
item={this.state.selectedItem}
closePopup={this.togglePopup.bind(this)}
/>
: null
}
);
}
}
List.js
import React from 'react';
import Item from './Item';
const List=({Items,onItemSelect,onClick})=>{
const renderedList= Items.map(item=>{
return (
<Item key={item.ID} item={item} onItemSelect={onItemSelect} onClick={onClick} />
);
})
return <div>
{renderedList}</div>
}
export default List;
Item.js
import React from 'react';
const Item=({item, onItemSelect,onClick})=>{
return <div onClick={()=>onItemSelect(item)} >
<div class="content">
<div class="header">
{/*display contents*/}
<button onClick={onClick}>View More</button>
</div>
</div>
};
export default Item;
Detail.js
import React from 'react';
const Detail=({item,closePopup})=>{
if (!item){
return <div>loading</div>
}
return (
<div>
<p>
{/*contents here*/}
</p>
<button onClick={()=>closePopup}>close me</button>
</div>);
};
export default Detail;
You have not set state to show popup, do this
onItemseSelect=(item)=>{
this.setState({selectedItem:item, showPopup: true}); //make showPopup to true so that popup get displayed
};
Note: As you are using arrow function, no need to bind this here,
closePopup={this.togglePopup.bind(this)}
You can change this to,
closePopup={this.togglePopup}
Another thing is, don't do this,
<div onClick={()=>onItemSelect(item) togglePopup={togglePopup}} > //This is wrong way to call two functions
<div onClick={()=> {onItemSelect(item); togglePopup;}} > //This is right way to call two functions
If you call togglePopup on every item click, then every time selectedItem:'' will set item to blank and you won't be able to see anything on page
Side note: Detail is a component and not a popup. This component will get display on App component after this.state.showPopup get true value. To show it as popup you must use Modal.

Custom namespaced attribute in JSX/React

As I already figured out, React's JSX doesn't support namespace tags by default. But lets say I have the following component:
render() {
return (
<div><!-- This should contain th:text -->
...
</div>
);
}
and I want this component to be rendered to:
<div th:text="value">
...
</div>
How can I achieve, that th:text="value" will be added to the rendered output?
Found the solution a few minutes later:
const i18n = {
"th:text": "${#foo.bar}"
};
render() {
return (
<div {...i18n}>
...
</div>
);
}

Resources