diff --git a/mangle.json b/mangle.json index cf506a61e8..6633035754 100644 --- a/mangle.json +++ b/mangle.json @@ -44,6 +44,7 @@ "$_force": "__e", "$_nextState": "__s", "$_renderCallbacks": "__h", + "$_stateCallbacks": "_sb", "$_vnode": "__v", "$_children": "__k", "$_pendingSuspensionCount": "__u", diff --git a/src/component.js b/src/component.js index cca3198eaf..f219acd7b5 100644 --- a/src/component.js +++ b/src/component.js @@ -47,7 +47,9 @@ Component.prototype.setState = function(update, callback) { if (update == null) return; if (this._vnode) { - if (callback) this._renderCallbacks.push(callback); + if (callback) { + this._stateCallbacks.push(callback); + } enqueueRender(this); } }; diff --git a/src/diff/index.js b/src/diff/index.js index e380895c29..fc564d3b20 100644 --- a/src/diff/index.js +++ b/src/diff/index.js @@ -89,6 +89,7 @@ export function diff( c._globalContext = globalContext; isNew = c._dirty = true; c._renderCallbacks = []; + c._stateCallbacks = []; } // Invoke getDerivedStateFromProps @@ -109,6 +110,11 @@ export function diff( oldProps = c.props; oldState = c.state; + for (tmp = 0; tmp < c._stateCallbacks.length; tmp++) { + c._renderCallbacks.push(c._stateCallbacks[tmp]); + c._stateCallbacks = []; + } + // Invoke pre-render lifecycle methods if (isNew) { if ( diff --git a/src/internal.d.ts b/src/internal.d.ts index 25e2ed0c47..57faa0ded0 100644 --- a/src/internal.d.ts +++ b/src/internal.d.ts @@ -133,6 +133,7 @@ export interface Component

extends preact.Component { _dirty: boolean; _force?: boolean; _renderCallbacks: Array<() => void>; // Only class components + _stateCallbacks: Array<() => void>; // Only class components _globalContext?: any; _vnode?: VNode

| null; _nextState?: S | null; // Only class components diff --git a/test/browser/lifecycles/componentDidUpdate.test.js b/test/browser/lifecycles/componentDidUpdate.test.js index 647adb8127..41bae1bf50 100644 --- a/test/browser/lifecycles/componentDidUpdate.test.js +++ b/test/browser/lifecycles/componentDidUpdate.test.js @@ -381,5 +381,55 @@ describe('Lifecycle methods', () => { expect(Inner.prototype.componentDidUpdate).to.have.been.called; expect(outerChildText).to.equal(`Outer: ${newValue.toString()}`); }); + + it('should not interfere with setState callbacks', () => { + let invocation; + + class Child extends Component { + componentDidMount() { + this.props.setValue(10); + } + render() { + return

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 ( + + this.setState({ count: i }, () => { + invocation = this.state; + }) + } + /> + ); + } + return null; + } + } + + render(, scratch); + + rerender(); + expect(invocation.count).to.equal(10); + }); }); });