I have a list of translated keys and react component content.
e.g :
list = [{ translation: "Hello <1>World</1>", content: "Hello <a href='#'>World</a>" },
{ translation: "A <1>B</1>", content: "A <a href='#'>B</a>" }]
The idea is to show a translated data from the list using the "translation" and the structure of "content" with Trans Component of i18next-react with a map function.
{list.map((item) => (
<Trans i18nKey={item.translation}>
{item.content}
</Trans>))}
Unfortunately, this doesn't seem to work at all, the outcome is only the translated string, without the structure that should came by the React Component content.
Any idea how to work around this?
Your content is a pure string and not a react element. Therefore your code can't work -> it can't extract the a element from the string and replace the <1> with it.
edit below
sample:
{list.map((item) => (
<Trans
i18nKey={item.translation}
defaults={item.translation} // Hello <0>World</>
components={[World]}
</Trans>))}
You need to pass in the components to get interpolated into the "pseudo" tags <0>...details also have a look at https://react.i18next.com/misc/using-with-icu-format (for props defaults, components, values)
Just in case anyone will try to do this in the future:
The way to do so is to use components props as Jamuhl mentioned.
And to pass there an array with the HTML elements of the "item.content".
The way to get the array of HTML elements from a string as we have on "item.content" is by using ReactHtmlParser that parse that string into an HTML elements array!
ReactHtmlParser can be cloned from here: https://www.npmjs.com/package/react-html-parser
For who still have problem.
make sure you have correct order of nested html
like
key ="<0><0/><1>translated here</1></0>";
function createMarkup()
{
return <div><input type="checkbox" /><label>translate here</label></div>;
}
<Trans i18nKey="key" >{ReactHtmlParser(createMarkup())}</Trans>
Related
I have a simple react component in which using ref I am getting the div but I have to generate a html includes styling as well. So I can pass this html to PDF generation backend server.
pdfRef(elem){
console.log(elem);
//<div><span>dataPDF</span> </div>
}
render() {
return (
<div ref={(elem) => this.pdfRef(elem)} className="SomeCssClass">
<span >dataPDF</span>
</div>
);
}
}
[Edit]
When I try to print the div via ref, the elements are printed with class name. But when I send this string to pdf service, since only html element is sent and class name without the actual css , the pdf is generated without style.
is there any way to generate html with css as as string so further it can be send to pdf service. Hope the question is clear
Any pointers?
The server.js script in react-dom lets you render a React component to static html string. You can require it in your code like:
const ReactDOMServer = require('react-dom/server');
Or using ES6 syntax:
import ReactDomServer from 'react-dom/server'
After this you can render your component to HTML string using the ReactDomServer.renderToString or ReactDomServer.renderToStaticMarkup functions as follows:
const htmlStr = ReactDomServer.renderToStaticMarkup(<MyComponent prop1={'value1'} />);
This looks almost exactly like ReactDom.render, except that it doesn't need the second parameter of dom node to render at, and the html string is returned. Additionally this method can be used on both client and server side. For your generate-pdf use case renderToStaticMarkup would suffice. If required check the documentation at following link for subtle difference between the two methods mentioned above: https://reactjs.org/docs/react-dom-server.html
Let's say I have a simple template string :
const foo = `<div>foo</div>`;
How do I go about rendering this template string as HTML ?
It renders it as plain text if I do the following :
return({ foo });
Output:
<div>foo</div>
Expected output:
foo
I think what you try to do is
const foo = `<div>foo</div>`;
<div dangerouslySetInnerHTML={{ __html: foo }}></div>
Related question.
React documentation.
You note reactjs as a tag here. Instead of specifying the html as a string, make foo a functional react component.
To do that, make sure you have import React as 'react';.
Then, set foo as the functional component, i.e.:
const foo = () => <div>foo</div>;
Then, you can use that wherever you please. React components are just functions (or classes) that return jsx.
Your question is fairly open-ended, so you may be looking for some of the above answers, but this is one approach.
Off the top of my head there's 2 ways to parse a string (doesn't have to be a tl) into HTML: .innerHTML property and the more powerful .insertAdjacentHTML() method.
Demo
var tl = `
<video src='http://media6000.dropshots.com/photos/1381926/20170326/005611.mp4' controls width='320'></video>`;
document.body.innerHTML = tl;
document.body.insertAdjacentHTML('afterbegin', tl);
if you want to show the string of html as html page its better to do this:
<text>{{ info | safe }}</text>
In my React app, I have stored a text template as an HTML string on the server which is passed up to the client to be rendered. Is it possible to render this HTML string in such a way that it can access it's parent component state/props? I've tried using dangerouslySetInnerHTML and ReactDOMServer.renderToString(), both of which render the string as HTML, but render {props.text} as a literal string, rather than a reference to the component's props.
For example, on the server I have stored:
<div>Welcome to my app</div>
<div>{props.message}</div>
<div>Have fun</div>
And the component
import React from "react"
import { connect } from "react-redux"
const mapStateToProps = (state) => {
return { state }
},
WelomeBody = (props) => {
return (
<div dangerouslySetInnerHTML={{"__html": props.state.welcomeMessageBody}} />
)
}
export default connect(mapStateToProps, null)(WelomeBody)
but this results in:
Welcome to my app
{props.message}
Have fun
Is there a way that this can be rendered so as to access the value of props.message, rather than just rendering it literally?
If what you have in mind is to send down a React component (in JSX syntax) from your server to your client and have the client somehow rehydrate/compile it into an actual, working component, this is not achievable that easily.
When you build and bundle your React app, only components that are statically referenced/imported in your application at compile time can be used at runtime on the browser.
So, in order to dynamically render a component from a template and embed variables into it, your choices are:
Render it into final HTML on your server, send down that HTML and have a simple React component perform dangerouslySetInnerHTML for it. But, like you've already observed, that content has to be the full HTML code, no templates, variables, JSX, etc. Everything is string and HTML at this point, no more processing.
Alternatively, send down a Markdown document and have a Markdown component parse it into HTML and display it.
Create a sophisticated component that can receive a string, parse it, tokenize it, substitute values in it, etc. Essentially, create your own template-processing component that can read a template (the string sent down from your server) and embed the appropriate values into it.
A simple solution (to substitute values into a template) would be:
function Filler(props) {
let html = props.template;
Object.keys(props).forEach(key => {
if (key !== "template")
html = html.replace("{" + key + "}", props[key]);
});
return <div dangerouslySetInnerHTML={{__html: html}} />;
}
and use it like
<Filler template={"<h1>Hello, {firstname} {lastname}</h1>"} firstname="John" lastname="Doe" />
But again, this is far from a full-fledged actual React component.
I'm working on a simple blog/CMS tool. In authoring content, I'm supporting an option to enter raw html/css. The user enters this content into a text area, and I can render this into a page using dangerouslySetInnerHtml. That works fine.
However, I'd really like to embed some React components the content as well. Ideally I'd like to enter something like this into a textarea...
<div>
<p>Some content</p>
<MyPictureComponent url="..." />
</div>
...and then render that into a page and have it create the MyPictureComponent.
I'll be storing the above "code" in a database, and rendering it dynamically as users view the "post". Is it possible to rendering that raw text as functioning React?
I saw this project (HTML to React), which seemed promising, bu that seems to only parse the HTML given to it, not tags for React components.
I found a way to do what I want, with the caveat that it's somewhat manual, and potentially dangerous. However, in my case, I'm creating a blog/CMS for a very limited audience, and the concern about users potentially inserting harmful content is non-existent.
My approach ended up using html-to-react (https://www.npmjs.com/package/html-to-react). Html-to-react accepts a string (containing raw HTML markup), and transforms it into a proper React component. By default, its parse() method doesn't properly handle React components (it just turns them into lower-case-named html elements). However, the library has a parseWithInstructions, which allows you to control how individual nodes in the component are rendered.
In my case, I want to enable certain React components to be rendered. One of those is my ExternalLink component. What follows is the method I use to transform some user-entered raw HTML into a React component that properly rendered my components.
updatePreview() {
// Combine the user-entered CSS and the user-entered HTML into a single string.
let outputPreview = "<div><style>" + this.state.cssValue + "</style><div>" + this.state.inputValue + "</div></div>";
let htmlToReactParser = new HtmlToReact.Parser();
let processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
let processingInstructions = [
{
// Custom <ExternalLink> processing
shouldProcessNode: function (node) {
return node.name === 'externallink';
},
processNode: function (node, children) {
let attribs = node.attribs;
return <ExternalLink {...attribs}>{children}</ExternalLink>
}
},
{
// Anything else
shouldProcessNode: function (node) {
return true;
},
processNode: processNodeDefinitions.processDefaultNode
}];
// Convert the HTML into a React component
let reactComponent = htmlToReactParser.parseWithInstructions(outputPreview, () => true,
processingInstructions);
// Now that we have a react component, we set it to the state.
// Our render() method includes a "{this.state.outputPreview}", which causes the
// component to be rendered.
this.setState({outputPreview: reactComponent, refreshPreviewTimer: null});
}
Note that outputString in the first line of the method will contain some raw text like this:
"<div>
<style></style>
<div>
<p>Here's a link:<p>
<ExternalLink url="http://www.google.com">Google</ExternalLink>
</div>
</div>"
There are some approaches I'll take to generalize this approach more, using a dictionary of strings to enable support for a wider range of Components. I'll also look at some approach to automatically importing the desired Component. (Currently, I'm manually importing all supported components.)
So, all credit goes to the author of html-to-react, though I may encourage him to include an example of rendering child components.
My code fetches a blob of HTML and renders it on the page. When the user selects some text within this blob, I want the selected text to be wrapped in its own span. (This is a "highlighting" feature similar Google Docs' comments system.)
If I were doing this with plain Javascript, I'd mutate the DOM on my own. But I'm not sure how to do this safely in React or where in the component lifetime I'd be able to do so.
Ideally, I could directly manipulate the Element corresponding to my HTML blob and use that directly within render(), but I don't know if this would play well with React's bookkeeping.
How can I do this in React without shooting myself in the foot?
EDIT:
Per request, some sample code. Let's say that our component receives these props:
{
id: 1337,
content: "<p>This is a paragraph with some <strong>markup</strong></p>",
highlights: [],
}
And renders something accordingly:
const Widget = React.createClass({
render() {
return <div dangerouslySetInnerHTML={{__html: this.props.content}} />
},
});
Now the component is updated with highlights: [{ start: 5, end: 10 }]. I want to have chars 5 through 10 wrapped in some <span>.
Is the right way to do this to just parse this.props.content as an Element, add the <span> in the right place, and dangerouslySetInnerHTML at the end?
Maybe you can store your <p> element with the text you want to highlight in your state. Like
this.state = {
willHighlight: <p>This is a <span>paragraph</span> with some <strong>markup</strong></p>
}
And then you can conditionaly render it. I think this is a better approach