diff --git a/src/component.js b/src/component.js index fe4b5e5e3c..9695020eb8 100644 --- a/src/component.js +++ b/src/component.js @@ -53,7 +53,7 @@ Component.prototype.setState = function(update, callback) { const internal = this._internal; if (update != null && internal) { - if (callback) internal._commitCallbacks.push(callback.bind(this)); + if (callback) internal._stateCallbacks.push(callback.bind(this)); internal.rerender(internal); } }; diff --git a/src/diff/mount.js b/src/diff/mount.js index 9e16ba406a..48a84a6e5d 100644 --- a/src/diff/mount.js +++ b/src/diff/mount.js @@ -367,6 +367,10 @@ function mountComponent(internal, startDom) { if (renderHook) renderHook(internal); if (ENABLE_CLASSES && internal.flags & TYPE_CLASS) { renderResult = c.render(c.props, c.state, c.context); + for (let i = 0; i < internal._stateCallbacks.length; i++) { + internal._commitCallbacks.push(internal._stateCallbacks[i]); + } + internal._stateCallbacks = []; // note: disable repeat render invocation for class components break; } else { diff --git a/src/diff/patch.js b/src/diff/patch.js index 545b282509..e21d8f98fb 100644 --- a/src/diff/patch.js +++ b/src/diff/patch.js @@ -244,6 +244,10 @@ function patchComponent(internal, newVNode) { c.props = newProps; c.state = c._nextState; internal.flags |= SKIP_CHILDREN; + for (let i = 0; i < internal._stateCallbacks.length; i++) { + internal._commitCallbacks.push(internal._stateCallbacks[i]); + } + internal._stateCallbacks = []; return; } @@ -265,6 +269,10 @@ function patchComponent(internal, newVNode) { if (renderHook) renderHook(internal); if (ENABLE_CLASSES && internal.flags & TYPE_CLASS) { renderResult = c.render(c.props, c.state, c.context); + for (let i = 0; i < internal._stateCallbacks.length; i++) { + internal._commitCallbacks.push(internal._stateCallbacks[i]); + } + internal._stateCallbacks = []; // note: disable repeat render invocation for class components break; } else { diff --git a/src/internal.d.ts b/src/internal.d.ts index cd186f6c98..30baf77adb 100644 --- a/src/internal.d.ts +++ b/src/internal.d.ts @@ -164,6 +164,7 @@ export interface Internal
{ _depth: number | null; /** Callbacks to invoke when this internal commits */ _commitCallbacks: Array<() => void>; + _stateCallbacks: Array<() => void>; // Only class components } export interface Component
extends preact.Component
{
diff --git a/src/tree.js b/src/tree.js
index 82a3103e10..1732320ce4 100644
--- a/src/tree.js
+++ b/src/tree.js
@@ -89,6 +89,7 @@ export function createInternal(vnode, parentInternal) {
_prevRef: null,
data: flags & TYPE_COMPONENT ? {} : null,
_commitCallbacks: flags & TYPE_COMPONENT ? [] : null,
+ _stateCallbacks: flags & TYPE_COMPONENT ? [] : null,
rerender: enqueueRender,
flags,
_children: null,
diff --git a/test/browser/lifecycles/componentDidMount.test.js b/test/browser/lifecycles/componentDidMount.test.js
index 086702b4c9..8ca136bfe5 100644
--- a/test/browser/lifecycles/componentDidMount.test.js
+++ b/test/browser/lifecycles/componentDidMount.test.js
@@ -1,4 +1,5 @@
import { createElement, render, Component } from 'preact';
+import { setupRerender } from 'preact/test-utils';
import { setupScratch, teardown } from '../../_util/helpers';
/** @jsx createElement */
@@ -6,9 +7,11 @@ import { setupScratch, teardown } from '../../_util/helpers';
describe('Lifecycle methods', () => {
/** @type {HTMLDivElement} */
let scratch;
+ let rerender;
beforeEach(() => {
scratch = setupScratch();
+ rerender = setupRerender();
});
afterEach(() => {
@@ -32,5 +35,32 @@ describe('Lifecycle methods', () => {
render(
Hello world
; + } + } + + class App extends Component { + constructor(props) { + super(props); + this.state = { + show: false, + count: null + }; + } + + componentDidMount() { + // eslint-disable-next-line + this.setState({ show: true }); + } + + componentDidUpdate() {} + + render() { + if (this.state.show) { + return ( +