I try to render a raw html (email). This html has an image.
<img src="http://www.gstatic.com/android/market_images/email/play_hydra_logo_email.png" alt="Google Play" style="border:none">
Live demo, showing image
But when I use dangerouslySetInnerHTML, the image is not rendered.
Live demo, not showing image
render() {
const content = `
<img src="http://www.gstatic.com/android/market_images/email/play_hydra_logo_email.png" alt="Google Play" style="border:none">
`;
return (
<div dangerouslySetInnerHTML={{__html: content}} />
);
}
How can I render it correctly? Thanks
UPDATE: I found if I change the image source to https, it will work.
Unfortunately, I don't have the control of the raw html, it is from email. How can I render image with url http?
It shows the error:
Mixed Content: The page at 'https://example.com' was loaded over
HTTPS, but requested an insecure resource
'http://www.gstatic.com/android/market_images/email/play_hydra_logo_email.png'.
This request has been blocked; the content must be served over HTTPS.
From the conversation in the comments, this appears to be linked to JSFiddle and possibly its use of iframes combined with requesting http resources from a https page.
Following the gnudi's reference, the RFC 3986 section 5.2 says:
If the scheme component is defined, indicating that the reference
starts with a scheme name, then the reference is interpreted as an
absolute URI and we are done. Otherwise, the reference URI's scheme is
inherited from the base URI's scheme component.
class App extends React.Component {
render() {
return (
<div>
<img src='//gstatic.com/android/market_images/email/play_hydra_logo_email.png' alt="Google Play"
style={{border: 'none'}}/>
</div>
);
}
}
ReactDOM.render(
<App />,
document.body
);
<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="react"></div>
Related
I'm using Gatsby to build a website that has a "specials" page with embedded Facebook. The Facebook embed does not display unless I manually reload the page or go directly to the "specials" page (rather than navigating to "specials" from the home page).
I have the Facebook script in my layout.js component file using React-Helmet:
export default ({ children }) => {
return (
<div id={layoutStyles.body}>
<Helmet>
// ...other tags
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v5.0"></script>
</Helmet>
<Navigation />
<div id={layoutStyles.main}>{children}</div>
<Footer />
</div>
)
}
And in my specials.js file I have the rest of the code for embedding:
// ...
render() {
return (
<Layout>
<div id="fb-root"></div>
<p>Scroll to see more specials.</p>
<div id={styles.facebook} className="fb-page" data-href="https://www.facebook.com/LakesideMarcell/" data-tabs="timeline" data-width="500" data-height="" data-small-header="true" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="https://www.facebook.com/LakesideMarcell/" className="fb-xfbml-parse-ignore">Lakeside Lumber & Hardware LLC</blockquote>
</div>
<p>If you don't see specials here click the link above to see our specials on Facebook.</p>
</Layout>
)
}
}
export default Specials
I've tried moving the script tag around in the code but the result is the same problem. I also tried using componentDidMount with state, and a function that called window.location.reload(), but I cold not get the page to reload only once.
I've used the same code embedded in a version of the website not using Gatsby and I don't have this issue so it must be something to do with Gatsby. Is there a way to fix this or reload the page once without user action?
I wonder if there's more or less official way to use class attribute instead of className in React.
And use normal names in style attribute {{ 'background-color': 'red' }} instead of its camel cased version {{ backgroundColor: 'red' }}.
Ideally with TypeScript support.
This behaviour is already supported in React 16 onwards, maybe not quite in the way you are expecting in your question. The style will not be processed as an JSX but as a string. In 15 the class attribute was ignored while in 16 it will be passed on
Refer the documentation for an explanation why this was changed.
https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html
Below snippet uses React 16
function MyComponent(props){
return <div class="myclass">Color Will be Red</div>
}
ReactDOM.render(
<MyComponent />,
document.getElementById("react")
);
<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>
<style>
.myclass {
color: red
}
</style>
<div id="react"></div>
Below snippet uses React 15
function MyComponent(props){
return <div class="myclass">Color Will not be Red</div>
}
ReactDOM.render(
<MyComponent />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.min.js"></script>
<style>
.myclass {
color: red
}
</style>
<div id="react"></div>
You can already use kebab case (e.g. 'background-color') in JSX style tags without issue, but using class in lieu of className is strongly discouraged in React.
The reason for the latter is that although the JSX your React components looks similar to HTML, it is actually an extension of JavaScript. Because class is a keyword in JavaScript, React throws a warning when you use it in JSX:
Warning: Invalid DOM property class. Did you mean className?
If you still want to use class for CSS class names, you can use the dangerouslySetInnerHTML attribute to set HTML from JSX. Use of this attribute isn't recommended for most use cases including yours, but it won't throw a warning:
const DivWithInnerHTML = () => (
<div
dangerouslySetInnerHTML={{
__html: `
<div class="css-class-name" style="background-color: red;">
html text
</div>
`
}}
/>
);
My HTML content is coming from an API (Gatsby in this case) so I'm using dangerouslySetInnerHTML as recommended. The thing is, it messes with my styling, specifically with grids. I have a html markup like this:
<article>
<h2>Title of the post<h2>
<small>Date of the post</small>
<div dangerouslySetInnerHTML={{ __html: post.html }} />
</article>
This <article> tag contains a display: grid style. But all the content inside that div is taking precious space making it hard to style (also it's not an useful div!). All the important html is inside but I want to get rid of the actual <div> tag. Is there any way to do it?
Note: I already tried to {post.html} it directly but it's encodedURI which can't be decoded.
Thank you!
Check out the react docs for dangerouslySetInnerHTML.
you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key...
So there's nothing stopping you from forming your own html string from different parts of your graphql query like so:
const createFullPostMarkup = () => {
return { __html: `<h2>Title of the post</h2><small>Date of the post</small>${ post.html }` }
}
And then setting it later as inner html on your article like this:
<article dangerouslySetInnerHTML={createFullPostMarkup()} />
Remember, this is just an object with a __html key. You can put anything in there.
Note: What I think you might be after is described by this open feature request. For your use case, i think the above solution works perfectly. But if you're still not satisfied, check out the discussion in the linked issue.
You can also do this:
/**
* Load CSS file in parallel vs a blocking <link /> tag
*
* #param {string} fontUrl The raw font URL
*/
const LoadCSSFile = ({ fontUrl }) => {
// hilariously bad hack to get around React's forced wrapper for dangerouslySetInnerHTML
// #see https://github.com/facebook/react/issues/12014#issuecomment-434534770
let linkStr = '</style>';
linkStr += `<link rel="preload" href="${fontUrl}" as="style" onload="this.rel='stylesheet'" />`;
linkStr += `<noscript><link rel="stylesheet" href="${fontUrl}"></noscript>`;
linkStr += '<style>';
return <style dangerouslySetInnerHTML={{ __html: linkStr }} />;
};
This will output as:
<style></style>
<link ... />
<noscript><link ... /></noscript>
<style></style>
Definitely not the most elegant solution but it should accomplish what you need until React supports dangerouslySetInnerHTML on fragments.
I'm trying to build an app where needs to get data before send props to <Helmet> but I don't know if it's possible because I don't see nothing like it in the docs.
And there's no possible to show this content in Helmet component. The content is always empty
The Helmet component is the HtmlPage component.
In the code below, we receive an SEO undefined error.
https://github.com/nfl/react-helmet/issues/409
<HtmlPage
{...this.props.client.info.SEO}
>
<ThemeProvider theme={this.state.theme}>
<div className='wrapper' id='wrapper'>
{loading && <Loading
client={this.state.client}
/>}
<div className="content" id='page-wrapper'>
<h1>Its ok for now ====</h1>
<p>
{JSON.stringify(this.props.client)}
</p>
<div>
{!!this.props.client.info &&
<p>{JSON.stringify(this.props.client.info.SEO)}</p>}
</div>
</div>
</div>
</ThemeProvider>
</HtmlPage>
The react-helmet-async don't work.
https://github.com/staylor/react-helmet-async
You need to implement a second renderPass to allow it to collect header elements. I tried react-tree-walker for this, but it didn't work. In the end I added a second renderPass using renderToStaticMarkup. E.g.
`
const stream = renderToNodeStream(<App preloadedState={preloadedState} />);
// extra render pass
renderPass(<App preloadedState={preloadedState} />);
`
I'm using the React 16 beta (react-fiber) with server side rendering
What I am to understand this to mean?
warning.js:36 Warning: Did not expect server HTML to contain a <div> in <div>.
Just change express response from
<body>
<div id="root">
${markup}
</div>
</body>
to
<body>
<div id="root">${markup}</div>
</body>
Remove space between tags
Looking for that error in the react code it seems that this happens when the SSR html can't be rehydrated.
https://github.com/facebook/react/blob/7a60a8092144e8ab2c85c6906dd4a7a5815cff1f/src/renderers/dom/fiber/ReactDOMFiberComponent.js#L1022
So you are somehow initially rendering a different tree on the client vs the server.
I faced the same warning while using Modal in Next.js. I was working to create a popup on the main page.
I found a solution. If the modal show state comes true first, it produces this warning. So I made it first undefined then I set it true after the page rendered . The code is below.
const [modalShow, setModalShow] = React.useState();
useEffect(() => {
if ( modalShow === undefined ) {
setModalShow(true)
}
}, [modalShow])
I had this issue, I solved it where I changed this:
<div>
<Header />
{children}
</div>
to this:
<div>
<Header />
<div>{children}</div>
</div>
My issue was react-loadable: The code used LoadableComponent for client only which wrapped each of my React-Component in client.
The cause was hard to find because Client and Server rendered the same HTML.
My Solution:
upgrade to node 16.x
remove react-loadable
load all components using import