Adminiculo
Adminiculo

Reputation: 333

Component get duplicated content instead of refreshing

I'm reviewing ReactJS, following the tutorial at https://facebook.github.io/react/docs/tutorial.html and when playing with the example I run into a weird behavior. The problem is that the content of one element (the comment) doesn't get refreshed . Instead it duplicates the new data.

See a working fiddle at http://jsfiddle.net/L0xy4jqa/2/

What's wrong?

CODE:

/* HTML */
<script src="http://fb.me/react-js-fiddle-integration.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
<div id="content"></div>

/* JS */
var DATA = [
        {author:"Mr. Raspa Pan", color:"darkblue", text: "- some content"},
        {author:"Mrs. Pasa Sa", color:"darkgreen", text: "- some *other* content"},
        {author:"Mrs. Rata Tan", color:"brown", text: "- __more__ content"},
        {author:"Mr. Aspa Spa", color:"deeppink", text: "- Code like:  `for (;true;) {lv(u)}`"}    
    ];

var DATA2 = [
        {"author":"Mrs. Raspa Pan Pan", "color":"blue", "text": ">- some *chaged* content"},
        {"author":"Mrs. Pasa Sa Sa", "color":"green", "text": ">- some *other* __changed__ content"},
        {"author":"Mr. Rata Tan Tan", "color":"red", "text": ">- __more__ **changed** content"},
        {"author":"Mr. Aspa Spa Spa", "color":"pink", "text": ">- Code like: `with (you) { lv(this); }`"}  
    ];

var Comment = React.createClass({
  render: function (){
    var markdown = marked(this.props.children.toString(), {sanitize: true});

    return(
      <div className="comment" style={{border: "1px solid orange", padding: "5px"}}>
        Hello, world! I am a comment from:
        <h2 className="commentAuthor" style={{color: this.props.color, border: "1px solid purple", margin: "0"}}>
          {this.props.author}
        </h2>
//This line below has the problem: it should be <div className="commentContent" ... in order to hold the <p> returned by marked
        <p className="commentContent" dangerouslySetInnerHTML={{__html: markdown}} />
      </div>
    );
  }
});

var CommentList = React.createClass({
  render: function(){
    var commentNodes = this.props.data.map(function (comment,i){ return(
        <Comment key={i} author={comment.author} color={comment.color}>{comment.text}</Comment>);
        }
      );
    return (
      <div className="commentList" style={{border: "1px dashed blue", padding: "5px"}}>
        Hello, world! I am a CommentList. And I have comments:
        {commentNodes}
      </div>
    );
  }
});

var CommentBox = React.createClass({
  getInitialState: function(){
    return {data: this.props.data};
  },
  componentDidMount: function () {
     var o = this;
    setTimeout(function(){
        o.setState({data: DATA2});
    },2000);      
  },
  render: function() {
    return (
      <div className="commentBox" style={{color: "grey", border: "1px solid red", padding: "5px"}}>
        Hello, world! I am a CommentBox and I have a list of comments.
        <CommentList data={this.state.data}/>
      </div>
    );
  }
});

React.render(
  <CommentBox data={DATA} url="comments.json"/>,
  document.getElementById('content')
);

Upvotes: 0

Views: 1161

Answers (1)

Adminiculo
Adminiculo

Reputation: 333

The problem is that marked library returns the formatted strings inside a <p> element. That is colliding with the JSX <p> container. The browser tries to fix the nested paragraph splitting them, causing React to lose the reference to the content. I'm editing the question to point the line with the issue.

So guys, be careful with the dangerouslySetInnerHTML param.

Upvotes: 1

Related Questions