Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dangerouslySetInnerHtml doesn't update during render

Tags:

reactjs

So I made a component for including content-editable components in my app. I copied it from some gist I believe, then edited to what i needed.

The code is below. When I edit it, it triggers updates on the parent just fine, but when I attempt to set props.html in the parent, it doesn't reflect in the UI. FURTHER, the console.log shows that this.props.html is equal to '' a blank string, yet the UI doesn't update, and maintains the text that was originally in there.

I don't understand how this is possible... dangerouslySetInnerHtml = {__html: ''} should make it so the UI reflects an empty string... it feels like it should be impossible for it to show the old text.

var React = require('react');

var ContentEditable = React.createClass({
    render: function(){
        //TODO: find where html=undefined and fix it! So I can remove this? Maybe I should keep this safety.
        var html = this.props.html || '';
        console.log('content editable render, html: ', this.props.html);
        return <div id="contenteditable"
            onInput={this.emitChange} 
            onBlur={this.emitChange}
            contentEditable
            dangerouslySetInnerHTML={{__html: html}}></div>;
    },
    shouldComponentUpdate: function(nextProps){
        return nextProps.html !== this.getDOMNode().innerHTML;
    },

    emitChange: function(){
        var html = this.getDOMNode().innerHTML;
        if (this.props.onChange && html !== this.lastHtml) {
            this.props.onChange({
                target: {
                    value: html
                }
            });
        }
        this.lastHtml = html;
    }
});

module.exports = ContentEditable;

(A little background, I'm trying to clear my input after submitting it to be saved. The clearing isn't working, hence this question.)

like image 654
Sophie McCarrell Avatar asked May 14 '15 16:05

Sophie McCarrell


2 Answers

I got a very similar problem using contentEditable and shouldComponentUpdate, it looks like there is a bug when resetting the innerHTML to the same previous value using dangerouslySetInnerHTML function (or prop) (I think it does not work even if you insert the code without using it) ... I suspect (this is just an idea) that React compares the last value set through dangerouslySetInnerHTML with the new one you are trying to send and decides not to update the component because it is the same (even if the real innerHtml has changed due to user interactions, because those interactions does not trigger any state or props update on React).

Solution: The easiest solution I found was to use a different key each time I needed it to re-render. for example using key={Date()}.

Example: Here you can find your code (I changed some of it to make it work), when you type '?' into the div, the text inside the ContentEditable component should become an empty string (i.e. ''), it works only once, the second time you type '?' won't work because the innerHTML for react will be the same to the one you're setting (i.e. an empty string so it won't update the component).

And here, I added the key={Date()} (this is the easiest way to show you that this work, but it is not the best way to set a unique key each time it re-render) to the editable component, now you can type any number of '?' and it will work.

like image 179
Mike W Avatar answered Oct 05 '22 17:10

Mike W


I found another solution that is probably better than generating random keys. Putting a key specifically on the div that calls #dangerouslySetInnerHtml, and not just on the component itself

<div class='wrapper'>    
<div key={this.props.thing.id} dangerouslySetInnerHtml={this.props.thing.content} />
</div>
like image 42
Brent L Avatar answered Oct 05 '22 17:10

Brent L