React JSX to string - reactjs

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.

Related

React - Call function from non-parent component with state from separate component

I'm attempting to call a function from an AppBar with the state from a child component, like so
// App.js
<BrowserRouter>
<Nav />
<Routes>
<Route exact path={"/"} element={<MyComponent/>}/>
<Routes>
</BrowserRouter>
//Nav.js
function Nav() {
return (
<div>
<h1>Hello World</h1>
<button onClick={logChildState}>Get State</button>
</div>
)
}
// MyComponent.js
function MyComponent() {
const [someState, setSomeState] = useState({
Some state values....
})
return (
<div>
<input />
...more components...
</div>
)
}
logChildState() == "Some state values...."
The goal is to have the AppBar have a button with a function call that captures the state of MyComponent. As this is a simplified example, I will just say that the state should exist in the child, and it's not possible to hoist the state to App.js - because of this, I don't see a way to accomlish what I'm looking for easily, I've looked at possibly achieving this using context or an observable but it would be quite messy.
I'm wondering what the best way to tackle this kind of issue would be, or if my best choice would just be to have the "button" in Nav.js in the MyComponent.js.
Thanks
You can add the function as a prop like this:
//Nav.js
function Nav({logChildState}) {
return (
<div>
<h1>Hello World</h1>
<button onClick={() => logChildState('send this message')}>Get State</button>
</div>
)
}
And in your app Component you can simply take it as a prop like this:
<Nav logChildState = {logChildState}/>
and if you want to print the message comming from Nav component simply do this in App.js
const logChildState = (message) => {
console.log(message);
}
Hope that helps!

Passing entire json like objects to react component as props at one go instead of individual props

index.js
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
const comment1 = {
"text":"Nice job",
"author_name":"Aru",
"avatarUrl": 'http://www.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802?d=identicon'
}
function CompleteComment(props){
const comment = props;
return (
<div className="UserInfo">
<img className="Avatar"
src={comment.avatarUrl}
alt={comment.author_name}
/>
<div className="UserInfo-name">
{comment.author_name}
</div>
<div className="comment">
Comment: {comment.text}
</div>
</div>
);
}
function App(){
return (
<div>
<!-- working,but only comment text is passed not all props -->
<CompleteComment text={comment1.text} />
<!-- Not Working -->
<CompleteComment comment={comment1} /> </div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
In the above code, i am trying to pass the entire comment1 JSON object to the react component as a single prop, instead of individual props. how do I do it? I am not getting the values, also please explain why I don't get any errors also.
You need to change the way you use the "comment" prop.
Change this
const comment = props;
to
const { comment } = props
Then this will work
<CompleteComment comment={comment1} />
Try this. This will work. You need to access comment of the props object.
function CompleteComment({ comment }){
return (
<div className="UserInfo">
<img className="Avatar"
src={comment.avatarUrl}
alt={comment.author_name}
/>
<div className="UserInfo-name">
{comment.author_name}
</div>
<div className="comment">
Comment: {comment.text}
</div>
</div>
);
}
Use spread operator:
<CompleteComment {...comment1} />

Can I call react component in a react component

I'm just start learning react js. Just wondering is it a good way to invoke a component inside another component?
Most React projects will start out by giving you an App.js component where you can start writing code. There, you can invoke other components using JSX syntax. Like this:
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
Working example below:
// Main application component
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
// Header component
function Header() {
return (
<header>
<h1>My first React App</h1>
</header>
)
}
// Main component
function Main() {
return (
<main>
<p>Stuff and stuff go here..</p>
</main>
)
}
// Footer component
function Footer() {
return (
<footer>
<p>Copyright 2020</p>
</footer>
)
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Note: You may also see class components instead of functional ones. They look something like this:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
// some state goes here..
}
}
render() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
}
You generally want to compose components using JSX. There is a good write up on the react docs. https://reactjs.org/docs/composition-vs-inheritance.html
const ComponentOne = () => <div>hi</div>
const ComponentTwo = () => <div>two</div>
const ComponentThree = () => (
<>
<ComponentOne />
<ComponentTwo />
</>
)
In the case that you want to learn, or start to le I recommend this https://reactjs.org/docs/getting-started.html. If you have another question please let me know.
React has two type of components: Function based and Class based. I will explain Function based components.
Example:
import React, {Fragment} from 'react';
function ComponentB(){
return (
<p>Hello i'm component B</p>
)
};//end;
function ComponentA(){
return (
<Fragment>
<h1>hello i'm component A</h1>
<ComponentB />
</Fragment>
)
};//end;
export default ComponentA;

Adding a Link as a child of a Router with ReactDOM.render yields "You should not use <Link> outside a <Router>"

I am looking for a way to use ReactDOM.render to create a Link within a react router. The setup more or less looks like this:
const router = (
<div>
<Router>
<Route path="/map" component={Map}/>
</Router>
</div>
);
The relevant parts of Map.jsx look like this:
const MapPopup = () => {
return (
<Link to={`/map/add`} />
)
}
class Map extends React.Component {
componentDidMount() {
this.map = L.map('map')
//...stuff...
this.map.on('contextmenu', event => {
popup
.setLatLng(event.latlng)
.addTo(this.map)
.setContent(
ReactDOM.render(
MapPopup(),
document.querySelector('.leaflet-popup-content')
)[0]
)
.openOn(this.map)
})
}
render() {
return (
<React.Fragment>
<div id="map" />
</React.Fragment>
)
}
}
I am basically trying to add a Link to the map popup provided by leaflet (I can't use react-leaflet for this project). If I however return the MapPopup directly in the render function it works (obviously not in the popup but the Link does work this way).
<React.Fragment>
<div id="map" />
<MapPopup />
</React.Fragment>
Does anyone have an idea how I can tackle this rather unusual problem?
I am using "react-router-dom": "4.3.1".
This is the expected error since <Link> component expects ancestor component to be of router type (<BrowserRouter>, <MemoryRouter>, <Router> ... ), refer this thread for a more details.
For your scenario to circumvent this limitation ReactDOM.createPortal could be utilized instead of ReactDOM.render:
<Route
path="/popup"
render={() => (
<Popup>
<div>
Some content goes here
<Link to="/map"> Back to map</Link>
</div>
</Popup>
)}
/>
where
class Popup extends React.Component {
render() {
return ReactDOM.createPortal(
this.props.children,
document.querySelector("#link-render-div")
);
}
}
and
Here is a demo for your reference

Gatsby XSS Prevention

I've read that React only prevents XSS in children and not props. Is this code an XSS vulnerability?
import React from "react"
import { graphql } from "gatsby"import Layout from "../components/layout"
export default ({ data }) => ( <Layout>
<h1>About {data.site.siteMetadata.title}</h1>
<p>{data.body}</p>
<img src={data.url} />
</Layout>
)
Should I be using children and call the component like this?
(data) => <Component>
<h1>About {data.site.siteMetadata.title}</h1>
<p>{data.body}</p>
<img src={data.url} />
</Component>
as opposed to:
(data) => <Component {data} />
That snippet isn't XSS vulnerable, you could check it out by yourself.
// import React and others ...
function MyComponent({ inject, children }) {
return (
<main>
<div>{inject}</div>
<div>{children}</div>
</main>
);
}
function App() {
return (
<MyComponent inject="<script>console.log('Executed from prop')</script>">
{'<script>console.log("Executed from children")</script>'}
</MyComponent>
);
}
Script tags are rendered as string nodes. The only way you have to bypass that is by using prop dangerouslySetInnerHTML, that way you get XSS vulnerable, hence the name.
I hope it helps!

Resources