I'm using create react app and I need to assign props values to a styles of the component. In this case background image 'url' is need to pass as props to styles.
I have tried a lot of solutions but none of them worked
I'm making a component named HeroSection with props including backgroundURL and videoURL, I'm then using a statement to assign backgroundImage if the prop videoURL is empty
Home.js
import React from "react";
import HeroSection from "./components/HeroSection";
function Home() {
return (
<div className="home">
<HeroSection
firstLine="Not just a team,"
secondLine="We are a "
autoType={[
"family of rebels",
"movement of ideas",
"collection of culture",
]}
backgroundURL="../assets/hero_pic.jpg"
videoURL=""
/>
</div>
);
}
export default Home;
HeroSection.jsx
import React from "react";
import Typed from "react-typed";
function HeroSection(props) {
return (
<div
className={
props.videoURL === "" ? "hero-section img-background" : "hero-section"
}
style={{
backgroundImage:
props.videoURL === "" ? `url(${this.props.backgroundURL})` : "none",
}}
>
<h2>
<span className="first-line">{props.firstLine}</span>
<br />
<span className="second-line">{props.secondLine}</span>
<Typed
strings={props.autoType}
typeSpeed={40}
loop={true}
backDelay={2000}
backSpeed={20}
/>
</h2>
</div>
);
}
export default HeroSection;
I HAVE ALSO TRIED THESE STATMENTS AND NONE OF THEM WORKED
props.videoURL === "" ? `url(${props.backgroundURL})` : "none",
props.videoURL === "" ? `url('file://${props.backgroundURL}')` : "none",
So the solution was very simple
It's due to how webpack handle your assets. Since I pass it just as a string, it can't know that it needs to bundle your png as an asset. In HeroSection I added import backgroundPic from '../assets/hero_pic.jpg' and then used it in the props backgroundURL={backgroundPic} of HeroSection
Thanks for #user3252327 for commenting the solution
I have the following code in one my components:
return <Box>{props.children}</Box>
All this does is return the contents in a nicely formatted <div> box. Now what I want to do is if there are any email addresses in props.children, I want to render those as links. So for example, if the content was as follows:
Hi my name is Foo, you can contact me at foo#bar.com.
Then I would like the component to return this:
<div class="box">
Hi my name is Foo, you can contact me at foo#bar.com.
<div>
How do I do this? I was thinking of using regex to find all email addresses and add the <a> tags to them, but that didn't seem to work. Any help is appreciated here!
You can use regex
const str = `Hi my name is Foo, you can contact me at foo#bar.com, foo#yan.net`;
console.log(str.replace(/(\w+#\w+.\w+)+/g, "<a href='mailto:$1'>$1</a>"));
Output:
"Hi my name is Foo, you can contact me at <a href='mailto:foo#bar.com'>foo#bar.com</a>, <a href='mailto:foo#yan.net'>foo#yan.net</a>"
I am assuming that "props.chaildren" text has only one email.
import React from 'react';
function isContainEmail() {
//Write your logic to find this and I am assuming this function will return email address otherwise null
return 'foo#bar.com';
}
function splitByEmail() {
// Do your logic to split the email from text and send both part in a array
return [
'Hi my name is Foo, you can contact me at',
'. Some others line go here',
];
}
function generateTemplateForUser(text) {
const email = isContainEmail(text);
if (!email) return <div className='box'>{text}</div>;
const linkProps = {
href: `mailto:${email}`,
};
const textSplittedByEmail = splitByEmail(text);
return (
<div className='box'>
{textSplittedByEmail[0]} <a {...linkProps}> {email}</a>
{textSplittedByEmail[1]}
</div>
);
}
function App(props) {
return (
<>
{/* Please pass your props.children value in place of hardcoded value */}
{generateTemplateForUser(
'Hi my name is Foo, you can contact me at foo#bar.com. Some others line go here....',
)}
</>
);
}
export default App;
This solution will not work if you can have multiple emails in your text. Feel free to comment if you have any doubts.
Update
If you have multiple emails in text, then please use html-react-parser.
import React from 'react';
import parser from 'html-react-parser';
// Copy from #denelvis's answer
const formatText = (text) => {
return text.replace(/(\w+#\w+.\w+)+/g, "<a href='mailto:$1'>$1</a>");
};
function App(props) {
return (
<>
{/* Please pass your props.children value in place of hardcoded value */}
{parser(
formatText(
'Hi my name is Foo, you can contact me at foo#bar.com. Some others line go here.Hi my name is Dummy, you can contact me at foo#bar.com'
)
)}
</>
);
}
export default App;
Stackblitz Link
I am not using React.
I am using Stenciljs.
I have the following .tsx file:
export class MyComponent {
#Prop() message: string;
render() {
return (<div>{this.message}</div>);
}
}
I want to do this instead:
import myTemplate from '../my-template.??';
export class MyComponent {
#Prop() message: string;
render() {
return (myTemplate);
}
}
with ../my-template.?? containing:
<div>{this.message}</div>
Is it possible and how ? Thanks in advance for any help :)
Yes, you can absolutely do this, there are just a couple of things you need to tidy up:
Main file
import { Template } from '../template'; // No need for file extension but we're using a named export so we need the curly braces around 'Template'
export class MyComponent {
#Prop() message: string;
render() {
return ( // You don't technically need the parentheses here as you're just returning one thing
<Template /> // When outputting an imported component, it goes in angle brackets and the backslash closes it like an HTML element
)
}
}
Template
import React from 'react'; // template needs React
export const Template = () => { // defining the export in this way is known as a named export
return (
<p>A message here</p>
)
}
Okay, so that's going to get you a message output which is from your template. However, you were asking about passing a message to that template for it to output. That's totally easy as well - you just need to get some props in there. Here is the modified version of the above:
Main file
import { Template } from '../template';
export class MyComponent {
#Prop() message: string;
render() {
return (
<Template messageToOutput={message} /> // The first argument is the name of the prop, the second is the variable you defined above
)
}
}
Template
import React from 'react';
export const Template = (props) => { // props are received here
return (
<p>{props.messageToOutput}</p> // props are used here
)
}
That's how you pass data around in React - hope that helps!
I am building a web app with ReactJS, on the home page I am using a ternary operator two render two different Fragment according to the state( if true or false).
my Code looks like:
import React, { Component, Fragment } from 'react'
import { Link } from 'react-router-dom'
class Home extends Component {
state = {
citySearch : false
}
render(){
return (
<div className="home-main">
{ !this.state.citySearch ? (
<Fragment>
<h2 className="home-heading">Search Cafés from your</h2>
<div className="home-buttons">
<button className="home-buttons">Near You</button>
<span>or</span>
<button onClick={this.ActivateCitySearch} className="home-buttons">City</button>
</div>
</Fragment>
)
: (
<Fragment>
<h2 className="home-heading">Search Cafés from your</h2>
<input className="search-café" placeholder="Enter your location"/>
<Link className="search-input"><i className="fas fa-search"></i></Link>
</Fragment>
)
}
</div>
)
}
}
export default Home
The code works but I get the following in the console
InvalidValueError: not an instance of HTMLInputElement
Does anyone know how to get rid of this error??
Thanks,
J
Here's what I tried and how it goes wrong.
This works:
<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />
This doesn't:
<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />
The description property is just a normal string of HTML content. However it's rendered as a string, not as HTML for some reason.
Any suggestions?
Is this.props.match.description a string or an object? If it's a string, it should be converted to HTML just fine. Example:
class App extends React.Component {
constructor() {
super();
this.state = {
description: '<h1 style="color:red;">something</h1>'
}
}
render() {
return (
<div dangerouslySetInnerHTML={{ __html: this.state.description }} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Result: http://codepen.io/ilanus/pen/QKgoLA?editors=1011
However if description is <h1 style="color:red;">something</h1> without the quotes '', you're going to get:
Object {
$$typeof: [object Symbol] {},
_owner: null,
key: null,
props: Object {
children: "something",
style: "color:red;"
},
ref: null,
type: "h1"
}
If It's a string and you don't see any HTML markup the only problem I see is wrong markup..
UPDATE
If you are dealing with HTML Entities, You need to decode them before sending them to dangerouslySetInnerHTML that's why it's called "dangerously" :)
Working example:
class App extends React.Component {
constructor() {
super();
this.state = {
description: '<p><strong>Our Opportunity:</strong></p>'
}
}
htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
render() {
return (
<div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
I use 'react-html-parser'
yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser';
<div> { ReactHtmlParser (html_string) } </div>
Source on npmjs.com
Lifting up #okram's comment for more visibility:
from its github description: Converts HTML strings directly into React
components avoiding the need to use dangerouslySetInnerHTML from
npmjs.com A utility for converting HTML strings into React components.
Avoids the use of dangerouslySetInnerHTML and converts standard HTML
elements, attributes and inline styles into their React equivalents.
Check if the text you're trying to append to the node is not escaped like this:
var prop = {
match: {
description: '<h1>Hi there!</h1>'
}
};
Instead of this:
var prop = {
match: {
description: '<h1>Hi there!</h1>'
}
};
if is escaped you should convert it from your server-side.
The node is text because is escaped
The node is a dom node because isn't escaped
If you have HTML in a string I would recommend using a package called html-react-parser.
Installation
NPM:
npm install html-react-parser
yarn:
yarn add html-react-parser
Usage
import parse from 'html-react-parser'
const yourHtmlString = '<h1>Hello</h1>'
code:
<div>
{parse(yourHtmlString)}
</div>
If you have control over where the string containing html is coming from (ie. somewhere in your app), you can benefit from the new <Fragment> API, doing something like:
import React, {Fragment} from 'react'
const stringsSomeWithHtml = {
testOne: (
<Fragment>
Some text <strong>wrapped with strong</strong>
</Fragment>
),
testTwo: `This is just a plain string, but it'll print fine too`,
}
...
render() {
return <div>{stringsSomeWithHtml[prop.key]}</div>
}
I use innerHTML together a ref to span:
import React, { useRef, useEffect, useState } from 'react';
export default function Sample() {
const spanRef = useRef<HTMLSpanElement>(null);
const [someHTML,] = useState("some <b>bold</b>");
useEffect(() => {
if (spanRef.current) {
spanRef.current.innerHTML = someHTML;
}
}, [spanRef.current, someHTML]);
return <div>
my custom text follows<br />
<span ref={spanRef} />
</div>
}
UPDATE:
I removed someHTML state and added comments to make the example more coincise around the concept.
/**
* example how to retrieve a reference to an html object
*/
import React, { useRef, useEffect } from 'react';
/**
* this component can be used into another for example <Sample/>
*/
export default function Sample() {
/**
* 1) spanRef is now a React.RefObject<HTMLSpanElement>
* initially created with null value
*/
const spanRef = useRef<HTMLSpanElement>(null);
/**
* 2) later, when spanRef changes because html span element with ref attribute,
* follow useEffect hook will triggered because of dependent [spanRef].
* in an if ( spanRef.current ) that states if spanRef assigned to valid html obj
* we do what we need : in this case through current.innerHTML
*/
useEffect(() => {
if (spanRef.current) {
spanRef.current.innerHTML = "some <b>bold</b>";
}
}, [spanRef]);
return <div>
my custom text follows<br />
{/* ref={spanRef] will update the React.RefObject `spanRef` when html obj ready */}
<span ref={spanRef} />
</div>
}
You just use dangerouslySetInnerHTML method of React
<div dangerouslySetInnerHTML={{ __html: htmlString }} />
Or you can implement more with this easy way: Render the HTML raw in React app
In my case, I used react-render-html
First install the package by npm i --save react-render-html
then,
import renderHTML from 'react-render-html';
renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")
I could not get npm build to work with react-html-parser. However, in my case, I was able to successfully make use of https://reactjs.org/docs/fragments.html. I had a requirement to show few html unicode characters , but they should not be directly embedded in the JSX. Within the JSX, it had to be picked from the Component's state. Component code snippet is given below :
constructor()
{
this.state = {
rankMap : {"5" : <Fragment>★ ★ ★ ★ ★</Fragment> ,
"4" : <Fragment>★ ★ ★ ★ ☆</Fragment>,
"3" : <Fragment>★ ★ ★ ☆ ☆</Fragment> ,
"2" : <Fragment>★ ★ ☆ ☆ ☆</Fragment>,
"1" : <Fragment>★ ☆ ☆ ☆ ☆</Fragment>}
};
}
render()
{
return (<div class="card-footer">
<small class="text-muted">{ this.state.rankMap["5"] }</small>
</div>);
}
i use https://www.npmjs.com/package/html-to-react
const HtmlToReactParser = require('html-to-react').Parser;
let htmlInput = html.template;
let htmlToReactParser = new HtmlToReactParser();
let reactElement = htmlToReactParser.parse(htmlInput);
return(<div>{reactElement}</div>)
You can also use parseReactHTMLComponent from Jumper Package. Just look at it, it's easy and you don't need to use JSX syntax.
https://codesandbox.io/s/jumper-module-react-simple-parser-3b8c9?file=/src/App.js .
More on Jumper:
https://github.com/Grano22/jumper/blob/master/components.js
NPM Package:
https://www.npmjs.com/package/jumper_react
// For typescript
import parse, { HTMLReactParserOptions } from "html-react-parser";
import { Element } from "domhandler/lib/node";
export function contentHandler(postContent: string) {
const options: HTMLReactParserOptions = {
replace: (domNode: Element) => {
if (domNode.attribs) {
if (domNode.attribs.id === 'shortcode') {
return <div className="leadform">Shortcode</div>;
}
}
},
};
return parse(postContent, options);
}
// Usage: contentHandler("<span>Hello World!</span>")
If you have control to the {this.props.match.description} and if you are using JSX. I would recommend not to use "dangerouslySetInnerHTML".
// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;
// Here is how you print
return (
{description}
);