I would like to add React component into the string as JSX like this
const name = World
const a = 'Hello, {name}'
return <div>{a}</div>
how can I get the following output
<div> Hello, World</div>
You don't need a string; instead, you also need to use JSX syntax (this won't work with a string):
const name = World;
const a = <>Hello, {name}</>;
return <div>{a}</div>;
you can just use another function component to get the other HTML part, and then add it to the main app return function inside {}, here is a working snippet:
function name() {
return ( World );
}
const App = () => {
const a = `Hello, `
return (
<div>{a} {name()}</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Related
I have a react component that has an event that gets called when a user clicks an item in a different component. The function that gets called is intended to display a Div on the web page. I can return an html string, to display the div, but I would rather but that HTML into its own component. My function gets called, but if I try to return a components (instead of raw html) it shows the div but not text. It just says [object Object]. The function that gets called looks like this:
function MyPage() {
const nodeHoverTooltip = (node) => {
return `<div>${node.name}</div>`;
//displays fine
};
const nodeClickDetails = (node) => {
if(node.nodeType === "somenode"){
return (<MyNodeDetails></MyNodeDetails>);
//this just displays [object, Object]
}else if (node.nodeType === "anotherNodeType"){
return `<div>Another Node Type Details</div>`;
//displays fine
}else{
return `<div>More Details</div>`;
//displays fine
}
};
return (
<div className="MyDiv">
<header className="header">Some Examples</header>
<section className="Main">
<ForceGraph
linksData={data.links}
nodesData={data.nodes}
nodeHoverTooltip={nodeHoverTooltip}
nodeClickDetails = {nodeClickDetails}
/>
</section>
</div>
);
}
export default MyPage;
MyNodeDetails.jsx Component:
function MyNodeDetails ({data}) {
return (
<div>
MyNodeDetails
</div>
)
}
export default MyNodeDetails
Is there a way to but the HTML into a component and not do raw HTML?
The function that's handling displaying the the HTML code is setting the innerHTML of an element to the html string being returned. When you convert a component, which is an object, to a string it gets converted to '[object Object]'. You need to use JSX instead of strings.
Here's an example to show the difference between both approaches. I doubt your rendering function is using dangerouslySetInnerHTML, but the idea of converting to string is what's important.
const { createRoot } = ReactDOM
const { useState } = React
const Test = () => <div>This is a test component</div>
const testHTML = '<div>This is a test html string</div>'
function App(){
const [component, setComponent] = useState()
const [html, setHTML] = useState();
function useJSX(){
setComponent(<Test />)
setHTML(testHTML)
}
function useHTML(){
setComponent(<div dangerouslySetInnerHTML={{__html: <Test/>}}></div>)
setHTML(<div dangerouslySetInnerHTML={{__html: testHTML}}></div>)
}
return (<div>
<button onClick={useJSX}>Use JSX</button>
<button onClick={useHTML}>Use HTML</button>
{component}
{html}
</div>)
}
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App tab="home" />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have a component where I want to append some stuff to the parent component passed by props. Something like:
function MyComponent(props : IMyProps) {
return ( {<props.parent>}{myStuff}{</props.parent>}
}
So I can call my new component like this:
<MyComponent parent={<h1 />} />
And MyComponent will append children to the h1 element. Can this be done?
parent is already is a JSX, but your problem is you haven't passed children which is representing myStuff
Note that React's components are only callable with the first-letter-capitalized names, so I've assigned parent to Parent, and in the meanwhile, I've also added React.Fragment to prevent undefined-value cases from parent.
const MyComponent = ({ parent }) => {
const Parent = parent || React.Fragment //convert it to a callable component
const myStuff = "Testing" //simulating your stuff
return <Parent>{myStuff}</Parent>
}
ReactDOM.render(
<MyComponent parent={({children}) => <h1>{children}</h1>}/>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
If you only want to pass <h1/>, you need to clone the element and pass children in MyComponent by React.cloneElement
const MyComponent = ({ parent }) => {
const myStuff = "Testing" //simulating your stuff
return React.cloneElement(parent, {}, myStuff)
}
ReactDOM.render(
<MyComponent parent={<h1/>}/>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I'm trying to render the message with html tags inside it. The rendering is working fine if the string is passed as prop, but when the same is passed from a variable the display text has encoded text.
Any idea how do I get it working in both scenarios.?
class Hello extends React.Component {
render() {
console.log(this.props.name)
return <div>{this.props.name}</div>;
}
}
ReactDOM.render(
<Hello name="<p>How are you?</p>" />,
document.getElementById('container') --> **<p>How are you?</p>**
);
class HelloOther extends React.Component {
render() {
const name = "<p>How are you?</p>"
return <Hello name={name} />;
}
}
ReactDOM.render(
<HelloOther />,
document.getElementById('container2') -- <p>How are you?</p> -- > why?
);
Fiddle link - https://jsfiddle.net/d6s7be1f/2/
class Hello extends React.Component {
createMarkup() {
return {__html: this.props.name};
}
render() {
return <div dangerouslySetInnerHTML={this.createMarkup()} />;
}
}
From React Docs:
In general, setting HTML from code is risky because it’s easy to
inadvertently expose your users to a cross-site scripting (XSS)
attack. So, you can set HTML directly from React, but you have to type
out dangerouslySetInnerHTML and pass an object with a __html key, to
remind yourself that it’s dangerous.
Unless you want to use dangerouslySetInnerHTML, you could use a regex to wrap the string with html tags. This way, you don't have to pass html entities in the string. You just pass the string and wrap the string with html tag using .replace() function.
Since you also want the string to be parsed as HTML, you could pass an extra prop to the Hello component that is then used to wrap the string with the desired html tag and also render the string nested within the desired html tag
function HTMLTag({ tag, children }) {
return React.createElement(tag, null, children);
}
class Hello extends React.Component {
render() {
const { name, tag } = this.props;
const str = name.replace(/(.+)/, `<${tag}>$1</${tag}>`);
return (
<div>
<HTMLTag tag={tag}>{str}</HTMLTag>
</div>
);
}
}
class HelloOther extends React.Component {
render() {
const name = "How are you?";
return <Hello name={name} tag="h3" />;
}
}
ReactDOM.render(
<Hello name="How are you?" tag="p" />,
document.getElementById('container')
);
ReactDOM.render(
<HelloOther />,
document.getElementById('container2')
);
<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="container"></div>
<div id="container2"></div>
I'm new to react and am trying to implement a simple for loop, as demonstrated in this other stackoverflow post. However, I cannot seem to make it work. I just want to run the component 5 (or any number of) times rather than map over an array or similar.
DEMO: https://stackblitz.com/edit/react-ekmvak
Take this example here:
index.js:
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import Test from './test';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<div>
for (var i=0; i < 5; i++) {
<Test />
}
</div>
);
}
}
render(<App />, document.getElementById('root'));
test.js
import React from "react";
export default function Test() {
return (
<p>test</p>
);
}
Can anyone tell me where I'm going wrong? I've tried to copy the other stackoverflow post and tried test() also. I still get this error:
Error in index.js (18:27) Identifier expected.
Thanks for any help here.
You're trying to use plain Javascript in JSX. You have the right idea but your syntax is wrong. Instead, move your Javascript code (for loop) out to your render() method (above the return())
render() {
let items = []
for (let i = 0; i < 5; i++) {
items.push(<Test key={i} />)
}
return (
<div>
{items}
</div>
);
}
Few things to note here:
Components that are being iterated over, need a unique key property. In this case, we can use the current value of i
Elements can be rendered in JSX by wrapping them in curly braces, shown above. { items }
JSX will accept you any valid JavaScript expressions, Declarative vs Imperative Programming maybe this source can help you. You can create a declarative solution like those shown by the other colleagues (and the best solution), and also you can wrap your imperative solution into a function or method.
const Test = () => {
return (
<p>test</p>
);
}
class App extends React.Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
createElements = () => {
const elments = [];
for (var i=0; i < 5; i++) {
elments.push(<Test />)
}
return elements;
}
render() {
return (
<div>
{this.createElements()}
</div>
);
}
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
You need a returned value inside the JSX to be able to display anything, here's how you can do that:
const Test = () => {
return (
<p>test</p>
);
}
class App extends React.Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<div> { Array.from(Array(5)).map(el => <Test />) } </div>
);
}
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
You can't use a for loop like this in your return. I would recommend you using a map for this and looping over an array. You can do this by simply creating an array and directly mapping over it :
[...Array(totalSteps)].map(el => el {
return (
<Test />
)
})
You will have to surround this whole block in {}. This will create an array of totalSteps items and return totalSteps <Test />. So if totalSteps is 5, you'll be rendering that component 5 times. This is how your final component should look like :
render() {
return (
<div>
{[...Array(totalSteps)].map(el => el {
return (
<Test />
)
})}
</div>
);
}
For Dynamic Implementation, you can just pass an object to the parameter and display its different values in different components.
We will use map to iterate through the array of objects. Following is the example code in this regard:
return (
<>
{userData.map((data,index)=>{
return <div key={index}>
<h2>{data.first_name} {data.last_name}</h2>
<p>{data.email}</p>
</div>
})}
</>
In my scenerio, the following code helped me to generically generate multiple cards on the same page using a loop (map):
{data.map((data1, id)=> {
return <div key={id} className='c-course-container-card'>
<Courses
courseid = {data1.courseid}
courselink = {data1.courselink}
img = {data1.imgpath}
coursetitle = {data1.coursetitle}
coursedesc = {data1.coursedesc}
/>
</div>
})}
Hope it helps! :)
Basically I have 3 custom attributes data-pageName, data-defaultOption, data-options.
The problem I have is that when I pass into my child component I get an unexpected token error because its something like this:
const pageContent = ({data-pageName, name, onChange, data-defaultOption, value, data-options}) => {
/*return here*/
};
Basically the - symbol is causing the error.
How do I include it as data-pageName and not read as data - pageName?
This is how I call the component:
<pageContent data-pageName={this.state.pageClicked} onChange={this.closeMenu} data-defaultOption={this.state.tmpDefaultOption} value={this.state.tmpValue} data-error={this.state.tmpError} data-options='a'/>
Dashes are not allowed in variable names. So, you have to use quotes ''
const Example = (props) =>
<div>{props['data-name']}</div>
ReactDOM.render(
<Example data-name="hello"/>,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app" />
When you destruct your child component props, you can assign its dashed variables to variables with new names.
const PageContent = ({ 'data-options': dataOptions }) => (
<div>...</div>
);
PageContent.propTypes = {
'data-options': PropTypes.string
};
When using dashes, you must wrap it inside single quotes.
render() {
const myProps = {
'data-pageName': this.state.pageClicked,
'data-defaultOption': this.state.tmpDefaultOption,
};
return <MyComponent {...myProps} />
}
You can then use this.props['data-pageName'] inside your child component.