Search code examples
node.jsreactjsrenderhtml-renderingreact-quill

How to render HTML from a prop coming from MongoDB


I can't make my prop render in HTML. I'm making an app for a Christian ministry and I want to be able to post like a blog, I got quill working but I can't show the results rendered, is showing pure HTML.

I'v been trying to follow the rules of react-render-html, but my experience is little, so I don't really know what I'm missing. I try use 'renderHTML' but it doesn't work.

Below is my code, and if you see the screenshot, you will see that the first card is showing the HTML tags.

import React from 'react';
import { Container, Card, Button, CardTitle, CardText, CardColumns, CardSubtitle, CardBody, Collapse } from 'reactstrap';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { connect } from 'react-redux';
import { getPosts, deletePost } from '../actions/postActions';
import PropTypes from 'prop-types';
import axios from 'axios';
import renderHTML from 'react-render-html';

import PostsForm from './extentions/PostsForm';


class Home extends React.Component {
    componentDidMount() {
        this.props.getPosts();
    }

    onDeleteClick = (id) => {
        this.props.deletePost(id);
    }

    constructor(props) {
        super(props);
        this.onEntering = this.onEntering.bind(this);
        this.onEntered = this.onEntered.bind(this);
        this.onExiting = this.onExiting.bind(this);
        this.onExited = this.onExited.bind(this);
        this.toggle = this.toggle.bind(this);
        this.state = {
            collapse: false, 
            status: 'Closed',
            ButtonText: "Submit Post"
        };
      }

    onEntering() {
        this.setState({ status: 'Opening...' });
      }

    onEntered() {
    this.setState({ status: 'Opened' });
    }

    onExiting() {
    this.setState({ status: 'Closing...' });
    }

    onExited() {
    this.setState({ status: 'Closed', ButtonText: "Submit Post" });
    }

    toggle() {
    this.setState(state => ({ collapse: !state.collapse, ButtonText: "Close" }));
    }

    formOpening = () => {
        this.setState({
            on: !this.state.on
        })
    }

    render(){
        const { posts } = this.props.post;
        return(
            <Container>
                <div style={{float: "left"}}><h5>Current state: {this.state.status}</h5></div>
                <div style={{float: "right"}}><Button
                    color="dark"
                    style={{marginButtom: '2rem'}}
                    onClick={this.toggle}>{this.state.ButtonText}</Button></div>
                <Collapse
                  isOpen={this.state.collapse}
                  onEntering={this.onEntering}
                  onEntered={this.onEntered}
                  onExiting={this.onExiting}
                  onExited={this.onExited}
                    style={{clear: "both"}}
                >
                  <Card>
                    <CardBody>
                     <PostsForm />
                    </CardBody>
                  </Card>
                </Collapse>
                <CardColumns style={{clear: "both"}}>
                    <TransitionGroup className="Posts">
                    {posts.map(({ _id, title, subtitle, postbody}) => (
                        <CSSTransition key={_id} timeout={500} classNames="fade">
                            <Card>
                                <CardBody>
                                    <Button className="remove-btn" color="danger" size="sm" onClick={this.onDeleteClick.bind(this, _id)}>&times;</Button>
                                    <CardTitle><h3>{title}</h3></CardTitle>
                                  <CardSubtitle><h4>{subtitle}</h4></CardSubtitle>
                                  <CardText>{postbody}</CardText>
                                  <Button>Read More</Button>
                                </CardBody>
                            </Card>
                        </CSSTransition>
                    ))}
                    </TransitionGroup>
                </CardColumns>
            </Container>
        )
    }
};

Home.propTypes = {
    getPosts: PropTypes.func.isRequired,
    post: PropTypes.object.isRequired
}

const mapStateToProps = (state) => ({
    post: state.post
});

export default connect(mapStateToProps, { getPosts, deletePost })(Home);

Screenshot of how it looks now

I would like to see that the cards are acting like

Body Text ect etc etc

not <p>Body Text ect etc etc</p>


Solution

  • You need to use dangerouslySetInnerHTML API.

    From React Docs, slightly modified:

    function createMarkup(html) {
      return {__html: html};
    }
    
    function MyComponent({html}) {
      return <div dangerouslySetInnerHTML={createMarkup(html)} />;
    }
    

    https://reactjs.org/docs/dom-elements.html