Preact: Found issue setInnerHTML and resolved for last preact (simple patch)

Created on 19 Aug 2017  路  3Comments  路  Source: preactjs/preact

With preact we ve got some issue from setInnerHTML on state change
Finally with lot of test, i found the clue of it: (and it's simple patch)

Line 154 change the line
} else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);

to
} else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating , null != props.dangerouslySetInnerHTML);

nota: comma between hydrating and null

feedback needed

Most helpful comment

Sorry i forgot to say that i changed a bit the code of innerDiffNode:

I added a new params and The code is

     innerDiffNode(dom, vchildren, context, mountAll, isHydrating, InnerHTML){
     ///..blablabla
     else if (!InnerHTML && !child && min < childrenLen) for (j = min; j < childrenLen; j++) {
     }

you can see i added InnerHTML to get the result of null != props.dangerouslySetInnerHTML

After changing that, it's completely resolved the problem of changing state for a component using a dangerouslySetInnerHTML

Ps: my application is quite complex, i use mobx with material-ui all working fully after changing this.

after that my popover displayed correctly after click on buttons

the website working with preact is:
https://www.skiscool.fr

The problem was from the main page when user click on button (bellow the menu on big buttons with ? )
You can check the size , i optimized react fully (from 500kb -> 100 kb) thanks to your preact and the last uglifyjs-webpack-plugin

Nota
(maybe interesting to know)
i use the last version of babel 7.0.0-alpha.20 and the version loose work fully with preact too

here a part of code of my component who use a popover who is the content changed from state:

To make it simpler for you (to help to reproduce the bug) i deleted code no need to understand

```
class HomePage extends Component {
state = {
popOverTitle: "",
popOverContent: "",
popOverOpen: false
};
componentWillMount() {
this.openPopover = this.openPopover.bind(this);
}
openPopover(event, checked) {
const currT = event.target;
const currTP = currT.parentNode.parentNode;
const anchorEL = $(currT).siblings('.fa');
if (checked) {
  this.setState({
    popOverContent: currTP.getAttribute('data-content'),
    popOverTitle: currTP.getAttribute('data-title'),
    anchorEl: anchorEL[0],
    popOverOpen: true,
  });
} else {
  this.setState({
    anchorEl: null,
    popOverOpen: false,
  });
}
}
closePopover(event) {
this.setState({
  anchorEl: null,
  popOverOpen: false,
});
}
getContentAnchorEl = () => {
return findDOMNode(this.tooltip);
};

render() {
const {anchorEl, popOverOpen, popOverTitle, popOverContent} = this.state;
return ( 
<div className={s.features}> 
    <MyLinkRender content="title" dataContent="my content" onRun={this.openPopover} state=        {popOverOpen}/>
    <Popover
      open={popOverOpen}
      getContentAnchorEl={this.getContentAnchorEl}
      anchorEl={anchorEl}
      onRequestClose={this.closePopover}
      className="popover bottom"
      role="tooltip"
    >
      <div className="arrow"></div>
      <div ref={(c) => {
        this.tooltip = c;
      }}>
        <h3 className="popover-title">{popOverTitle}</h3>
        <div className="popover-content" ref={(c) => {
          this.popoverC = c;
        }} dangerouslySetInnerHTML={{__html: "<div>" + popOverContent + "</div>"}}/>
      </div>
    </Popover>
  </div>
 )
}
}
```

All 3 comments

Hi there,

By adding the comma, you're passing the result of null != props.dangerouslySetInnerHTML as a 6th argument to innerDiffNode, which only accepts 5 arguments. This has the same effect as removing the code entirely, so it's unlikely to be correct.

Can you provide more details about the issue you're running into?

Sorry i forgot to say that i changed a bit the code of innerDiffNode:

I added a new params and The code is

     innerDiffNode(dom, vchildren, context, mountAll, isHydrating, InnerHTML){
     ///..blablabla
     else if (!InnerHTML && !child && min < childrenLen) for (j = min; j < childrenLen; j++) {
     }

you can see i added InnerHTML to get the result of null != props.dangerouslySetInnerHTML

After changing that, it's completely resolved the problem of changing state for a component using a dangerouslySetInnerHTML

Ps: my application is quite complex, i use mobx with material-ui all working fully after changing this.

after that my popover displayed correctly after click on buttons

the website working with preact is:
https://www.skiscool.fr

The problem was from the main page when user click on button (bellow the menu on big buttons with ? )
You can check the size , i optimized react fully (from 500kb -> 100 kb) thanks to your preact and the last uglifyjs-webpack-plugin

Nota
(maybe interesting to know)
i use the last version of babel 7.0.0-alpha.20 and the version loose work fully with preact too

here a part of code of my component who use a popover who is the content changed from state:

To make it simpler for you (to help to reproduce the bug) i deleted code no need to understand

```
class HomePage extends Component {
state = {
popOverTitle: "",
popOverContent: "",
popOverOpen: false
};
componentWillMount() {
this.openPopover = this.openPopover.bind(this);
}
openPopover(event, checked) {
const currT = event.target;
const currTP = currT.parentNode.parentNode;
const anchorEL = $(currT).siblings('.fa');
if (checked) {
  this.setState({
    popOverContent: currTP.getAttribute('data-content'),
    popOverTitle: currTP.getAttribute('data-title'),
    anchorEl: anchorEL[0],
    popOverOpen: true,
  });
} else {
  this.setState({
    anchorEl: null,
    popOverOpen: false,
  });
}
}
closePopover(event) {
this.setState({
  anchorEl: null,
  popOverOpen: false,
});
}
getContentAnchorEl = () => {
return findDOMNode(this.tooltip);
};

render() {
const {anchorEl, popOverOpen, popOverTitle, popOverContent} = this.state;
return ( 
<div className={s.features}> 
    <MyLinkRender content="title" dataContent="my content" onRun={this.openPopover} state=        {popOverOpen}/>
    <Popover
      open={popOverOpen}
      getContentAnchorEl={this.getContentAnchorEl}
      anchorEl={anchorEl}
      onRequestClose={this.closePopover}
      className="popover bottom"
      role="tooltip"
    >
      <div className="arrow"></div>
      <div ref={(c) => {
        this.tooltip = c;
      }}>
        <h3 className="popover-title">{popOverTitle}</h3>
        <div className="popover-content" ref={(c) => {
          this.popoverC = c;
        }} dangerouslySetInnerHTML={{__html: "<div>" + popOverContent + "</div>"}}/>
      </div>
    </Popover>
  </div>
 )
}
}
```

With Preact X the content of dangerouslySetInnerHTML will only change, when the actual value does :tada:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nopantsmonkey picture nopantsmonkey  路  3Comments

skaraman picture skaraman  路  3Comments

marcosguti picture marcosguti  路  3Comments

rajaraodv picture rajaraodv  路  3Comments

kossnocorp picture kossnocorp  路  3Comments