Render html saved from draft-js - javascript

I'm learning React: totally newbie.
If I save in DB the HTML directly from draft.js (or it's variants always based on it) and then in a view page of my React SPA I retrieve HTML from DB through my API:
QUESTIONS:
how can I render that HTML?
dangerouslySetInnerHTML? Or maybe one of this (what do you suggest?)?
https://github.com/wrakky/react-html-parser
https://github.com/pveyes/htmr
https://github.com/remarkablemark/html-react-parser
https://github.com/utatti/react-render-html
https://github.com/aknuds1/html-to-react
I read words like "sanitize", "securing HTML". But how, there is a library?
I need to secure html from draft-js when I save it in DB or after, when I'm rendering it?

Draft-JS doesn't allows you to directly generate HTML from the present EditorState and that's a good thing. Since you are not dealing with "Raw HTML" you don't have to deal with XSS attacks as Draft Editors internal state won't get altered if someone inserts a script in the Editor.
Draft JS allows you the export the current Editor state so that you can store it easily. It can be done using
import {convertToRaw} from 'draft-js';
and in your onChange Handler you can simply do
const editorJSON = JSON.stringify(convertToRaw(editorState.getCurrentContent()));
You can the store this JSON as you like for future use.
Now for Rendering this you have two options :
Generate HTML from the stored EditorState.
This can be done using Libraries like https://www.npmjs.com/package/draft-js-export-html. You might want to avoid this as the next option in my opinion is way better.
Use this EditorState as the Default value for a read only DraftJS Editor Component.
You are going to need convertFromRaw from DraftJS Library and then you make a Nice StateLess React Component like this
import React from 'react';
import {Editor, ConvertFromRaw} from 'draft-js';
const ReadOnlyEditor = (props) => {
const storedState = ConvertFromRaw(JSON.parse(props.storedState));
return (
<div className="readonly-editor">
<Editor editorState={storedState} readOnly={true} />
</div>
);
}
And Now you can simply use this to display your contents. You can also pass your decorators and custom mapping functions, typically everything you pass to the normal Editor and can render the content without loss of style and tedious dealing with HTML.

DO NOT Believe USERS!
The first thing you should care of is "Do NOT believe your USERS".
If your 'HTML' is rendered by your server and can't be modified by user, it's totally OK.
Because your rendered/saved HTML is totally safe and managed by yourself, and if it's assured as "SAFE" HTML, whether you put it(html) into DOM or not is not the problem at all.
But the problem is, most of WYSIWYG editors - like draft.js- makes "HTML" files not TEXT. I think your worry comes from here too.
Yes, It's dangerous. what we can do is NOT rendering HTML directly but "selective" HTML rendering.
Dangerous tags : <script>, <img>, <link>, etc.
you can remove those tags but it can be much safer when you decide which tags will you allow, like this:
Safe tags: <H1> - <H6> / span / div / p / ol ul li / table...
and you SHOULD remove those HTML element's attributes, like, onclick="", etc.
because it could be abused by users too.
Conclusion:
So what can we do when we use WYSIWYG editors?
There are 2 big strategies:
Generate "Safe" HTML when safe to Database.
Generate "Safe" HTML before putting it into DOM.
(3. Generate "Safe" HTML before sending html to client, but it is not in your case!)
Choose first one if you want to sure Database's text are totally safe.
First one must be processed in your server(not browser/client!), and you can use many solutions like BeautifulSoup in python, or sanitize-html in nodejs.
Choose second one if your web-app is complicated, and most of your service's business logic is running on front-end side.
Second one is using HTML escaping package just before mounting HTML into DOM. and still sanitize-html can be good solution. (surelly there's more great solutions!)
You can decide which tags/attribute/values in HTML.
Links
https://github.com/punkave/sanitize-html

in 2022 for me, it works a bit different way
import { convertFromRaw, Editor, EditorState } from 'draft-js';
function Comments() {
const itemText= EditorState.createWithContent(convertFromRaw(JSON.parse(item.content)));
return <Editor editorState={itemText} readOnly={true} />
}
and to the DB it was saved like that
JSON.stringify(convertToRaw(editorState.getCurrentContent()))
the difference is that for me without EditorState it doesn't work, I believe that I am not alone in that

Related

Svelte render markup from variable

Problem I'm trying to solve:
I want to have one file with exports, info.js, that are variables including markup or pure strings.
For example;
export const title = "Some title"
export const mainText = (<b> I'm so texty </b>, mark me up like I'm a hot reloadable)
In JSX world, mainText is fine, in Svelte world, mainText needs to be a string which I then load with the #html thingy {#html mainText}.
Semi solution with issue I'd like input on:
Although, when I load with #html, the styles within the .svelte file are not applied. Fine, I can do that with :global, but... my second issue is that markup in a string is annoying too - can't prettify it.
What should I be doing?
Create a separate file for html-like syntax, markup in a string won't be very pretty, not much to do about it. You can load and parse .html from the back-end or something, but it's not the best thing as well.
Styles should be global, because it's not intended to work in this way (scoping out of box), but you can have your separate styles file as well in the static folder or send from the back-end with html as a separate and independent page.
Generally, I'd advise to refactor everything, so you can use Svelte as it's supposed to be used.

Is it possible to render HTML in react without using dangerouslySetInnerHtml

Long story short I have strings that contain HTML which are downloaded before a production build from a secure server. The framework we're using is React with Gatsby and typically you would just do the following:
<div dangerouslySetInnerHTML={{__html: '<p>My Stuff</p>'}}></div>
Which works fine, the main problem is for SEO purposes we want the html to be compiled into html rather than being rendered with Javascript.
Seeing as it's already HTML is there a way I can disable the protection inside react so these strings aren't escaped by default and become regular HTML in the production build?
Not practically, no. It's important to distinguish a <div> in a .jsx file from a <div> in html. If you look at the compiled output of the jsx, it will reveal what's really going on. If you transpile a react component containing <div>Hello world</div>, you'll get a function call along the lines of _react.createElement("div", null, "Hello world"). Anything that is put into the body of the div will also be inserted into it as JSX elements. The dangerouslySetInnerHtml prop is there to tell React that the value is actual html that you trust. However, even if there were an option other than dangerouslySetInnerHtml, I don't believe it would solve your problem as anything inside your react is going to have to wait for client side rendering.
Now, I'm no SEO expert, but if it's crucial to have content on the page before you render it, you may be able to send in the original html in a hidden element. If your original markup has <div id="app">Some seo stuff</div>, React will replace the content of the div when it renders it.
I think what you need is SSR; React allows this feature
You could install a server adapter (maybe expressjs) and use it to render a first screen (which is most likely SEO related) and once the client side is ready to render, it would hydrate the pages. Since you have the HTML gotten from a server, I think this is best route to go
var stringToHTML = function(htmlContent) {
var dom = document.getElementById('integrationMessage');
dom.innerHTML = htmlContent;
return dom;
};
stringToHTML(res.data.message);
<div id = "integrationMessage"></div>

What is correct way of passing html tags in React State?

I am in process of creating Blog using React. I am planning to bring main content of blog from server and passed to React Component via Props/State. Blog content can have html tags like :
blockquote
h2 and h3
img, Video, embed code etc etc
I was hoping to store content of blog in Database/json files along with these tags and render the content as it is on page load.
But It seems to be difficult to do it in React. There are three ways we can achieve this :
dangerouslySetInnerHTML
Storing content in form array object [html content] ( pushing a String content to array won't work ).
Passing unicode characters for all html entities.
This Question discuss these approaches pretty well :
Rendering raw html with reactjs
My Queries are :
Should there be change in over all flow/architecture to handle this?
What is best way to insert large html content from ajax call to react component to render ?
What design decisions should be considered to make fully functional and dynamic/scalable Blog ?
How to get SEO on your dynamic content like blog content ( which is stored in some file/database ). ?
There is nothing special about dangerouslySetInnerHTML. Rendering HTML from javascript could always be dangerous, regardless of using React or not, depending on the source of said HTML. For example, if you are rendering a post that you created yourself, and saved to a database, then there is no danger (unless your database has been compromised). But let's say you have comments on a post, and an user sends malicious code as a comment. All other users accessing that page, would fetch the malicious code from the database, and "dangerously" execute it on their browsers. So, what you need to do, is make sure the source of HTML is secure, by sanitizing any user input BEFORE saving to the database. There are libraries you can use to achieve that, example - http://htmlpurifier.org/
Regarding SEO, you can use server side rendering - https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express/
Make sure you have all the information you need available on the url, so you don't rely on "state" to render a page, like post id, etc. You can achieve that by using React Router - https://github.com/reactjs/react-router

Render HTML tags properly in React

I have to create a text module in React, i'm using JSX too; I will receive the data from a JSON file. For example:
{ "text-data":
"text": "<small> Hello world </small>"
}
I tried to do something like this in my module:
<p> {this.props.textData.text}</p>
When I try to render this in my JSX file, it show as plain text with the tags included. I've been researching and I found that I could use this function "Dangerously Set innerHTML" but it's not recommended because it can cause an XSS attack. I read here other answers about this, that say that using HTML entities work; but I can't make that work for now.
The dangerouslySetInnerHTML prop is there for cases like this. In effect, you're saying that you completely trust the html that you're outputting and that it's valid html. You would not want to use it for user input (unless absolutely necessary and thoroughly validated).
See the React documentation for more information. There is also a previous similar StackOverflow question.

Strategy for making React image gallery SEO-friendly

I wrote a React image gallery or slideshow. I need to make the alt text indexable by search engines, but because my server is in PHP, React.renderToString is of limited use.
The server is in PHP + MySQL. The PHP uses Smarty, a decent PHP template engine, to render the HTML. The rest of the PHP framework is my own. The Smarty template has this single ungainly line:
<script>
var GalleryData = {$gallery};
</script>
which is rendered by the PHP's controller function as follows:
return array(
'gallery' => json_encode($gallery),
);
($gallery being the result table of a MySQL query).
And my .js:
React.render(<Gallery gallery={GalleryData} />, $('.gallery').get(0));
Not the most elegant setup, but given that my server is in PHP there doesn't seem to be much of a better way to do it (?)
I did a super quick hack to fix this at first shot - I copied the rendered HTML from Firebug, and manually inserted it into a new table in the DB. I then simply render this blob of code from PHP and we're good to go on the browser.
There was one complication which is that because React components are only inserted into the DOM as they're first rendered (as I understand it), and because the gallery only shows one image slide at a time, I had to manually click through all slides once before saving the HTML code out.
Now however the alt text is editable by CMS and so I need to automate this process, or come up with a better solution.
Rewriting the server in Node.js is out of the question.
My first guess is that I need to install Node, and write a script that creates the same React component. Because the input data (including the alt text) has to come from MySQL, I have a few choices:
connect to the MySQL DB from Note, and replicate the query
create a response URL on the PHP side that returns only the JSON (putting the SQL query into a common function)
fetch the entire page in Node but extracting GalleryData will be a mess
I then have to ensure that all components are rendered into the DOM, so I can script that by manually calling the nextSlide() method as many times as there are slides (less one).
Finally I'll save the rendered DOM into the DB again (so the Node script will require a MySQL connection after all - maybe the 1st option is the best).
This whole process seems very complicated for such a basic requirement. Am I missing something?
I'm completely new to Node and the whole idea of building a DOM outside of the browser is basically new to me. I don't mind introducing Node into my architecture but it will only be to support React being used on the front-end.
Note that the website has about 15,000 pageviews a month, so massive scalability isn't a consideration - I don't use any page caching as it simply isn't needed for this volume of traffic.
I'm likely to have a few React components that need to be rendered statically like this, but maintaining a small technical overhead (e.g. maintaing a set of parallel SQL queries in Node) won't be a big problem.
Can anyone guide me here?
I think you should try rendering React components on server-side using PHP. Here is a PHP lib to do that.
But, yes, you'll basically need to use V8js from your PHP code. However, it's kind of experimental and you may need to use other around. (And this "other way around" may be using Node/Express to render your component. Here is some thoughts on how to do it.)

Categories