diff --git a/src/diff/index.js b/src/diff/index.js
index af4d02ea26..fc7b36b537 100644
--- a/src/diff/index.js
+++ b/src/diff/index.js
@@ -90,8 +90,11 @@ export function diff(parentDom, newVNode, oldVNode, context, isSvg, excessDomChi
c.state = c._nextState;
c._dirty = false;
c._vnode = newVNode;
- newVNode._dom = oldDom!=null ? oldVNode._dom : null;
+ newVNode._dom = oldDom!=null ? oldDom!==oldVNode._dom ? oldDom : oldVNode._dom : null;
newVNode._children = oldVNode._children;
+ for (tmp = 0; tmp < newVNode._children.length; tmp++) {
+ if (newVNode._children[tmp]) newVNode._children[tmp]._parent = newVNode;
+ }
break outer;
}
diff --git a/test/browser/lifecycles/shouldComponentUpdate.test.js b/test/browser/lifecycles/shouldComponentUpdate.test.js
index bca70b8468..641a8afcfa 100644
--- a/test/browser/lifecycles/shouldComponentUpdate.test.js
+++ b/test/browser/lifecycles/shouldComponentUpdate.test.js
@@ -1,5 +1,5 @@
import { setupRerender } from 'preact/test-utils';
-import { createElement, render, Component } from '../../../src/index';
+import { createElement, render, Component, Fragment } from '../../../src/index';
import { setupScratch, teardown } from '../../_util/helpers';
/** @jsx createElement */
@@ -294,9 +294,9 @@ describe('Lifecycle methods', () => {
});
// issue #1864
- it('should update dom pointers correctly', () => {
+ it('should update dom pointers correctly when returning an empty string', () => {
function Child({ showMe, counter }) {
- return showMe ?
Counter: {counter}
: null;
+ return showMe ? Counter: {counter}
: '';
}
class Parent extends Component {
@@ -362,5 +362,192 @@ describe('Lifecycle methods', () => {
rerender();
expect(scratch.textContent).to.equal('');
});
+
+ // issue #1864 second case
+ it('should update dom pointers correctly when returning a string', () => {
+ function Child({ showMe, counter }) {
+ return showMe ? Counter: {counter}
: 'foo';
+ }
+
+ class Parent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return ;
+ }
+ }
+
+ let updateChild = () => null;
+ class Inner extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showMe: false };
+ updateChild = () => {
+ this.setState({ showMe: display = !display });
+ };
+ }
+ render() {
+ return ;
+ }
+ }
+
+ let display = false;
+ let updateApp = () => null;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ updateApp = () => this.setState({});
+ }
+ render() {
+ return (
+
+ );
+ }
+ }
+
+ render(, scratch);
+ expect(scratch.textContent).to.equal('foo');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+
+ updateApp();
+ rerender();
+ expect(scratch.textContent).to.equal('foo');
+ });
+
+ it('should correctly update nested chilreen', () => {
+ let hideThree, incrementThree;
+
+ class One extends Component {
+ shouldComponentUpdate() { return false; }
+ render(p) { return p.children; }
+ }
+
+ class Two extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { hideMe: false };
+ hideThree = () => this.setState(s => ({ hideMe: !s.hideMe }));
+ }
+
+ shouldComponentUpdate(nextProps, nextState) { return this.state.hideMe !== nextState.hideMe; }
+
+ render(p, { hideMe }) {
+ return hideMe ? : p.children;
+ }
+ }
+
+ class Three extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { counter: 1 };
+ incrementThree = () => this.setState(s => ({ counter: s.counter + 1 }));
+ }
+
+ render(p, { counter }) { return {counter}; }
+ }
+
+ render(, scratch);
+ expect(scratch.innerHTML).to.equal('1');
+
+ hideThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+
+ hideThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('1');
+
+ incrementThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('2');
+ });
+
+ // issue #1864 third case
+ it('should update dom pointers correctly without siblings', () => {
+ function Child({ showMe, counter }) {
+ return showMe ? Counter: {counter}
: 'foo';
+ }
+
+ class Parent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return ;
+ }
+ }
+
+ let updateChild = () => null;
+ class Inner extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showMe: false };
+ updateChild = () => {
+ this.setState({ showMe: display = !display });
+ };
+ }
+ render() {
+ return ;
+ }
+ }
+
+ let display = false;
+ let updateApp = () => null;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ updateApp = () => this.setState({});
+ }
+ render() {
+ return (
+
+ );
+ }
+ }
+
+ render(, scratch);
+ expect(scratch.textContent).to.equal('foo');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+ });
});
});