From 232f88a75e60108d487263cd707202eba017cb14 Mon Sep 17 00:00:00 2001 From: Charles Lee Date: Thu, 3 Jan 2019 13:26:41 +1100 Subject: [PATCH 1/2] wrap logic in getWidth in windows.RAF, to resolve edge case with removed and appended portalled elements --- src/animated/transitions.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/animated/transitions.js b/src/animated/transitions.js index c6763b174d..4fa304bb42 100644 --- a/src/animated/transitions.js +++ b/src/animated/transitions.js @@ -71,9 +71,18 @@ export class Collapse extends Component { // width must be calculated; cannot transition from `undefined` to `number` getWidth = (ref: ElementRef<*>) => { if (ref && isNaN(this.state.width)) { + /* + Here we're invoking requestAnimationFrame with a callback invoking our + call to getBoundingClientRect and setState in order to resolve an edge case + around portalling. Certain portalling solutions briefly remove children from the DOM + before appending them to the target node. This is to avoid us trying to call getBoundingClientrect + while the Select component is in this state. + */ // cannot use `offsetWidth` because it is rounded - const { width } = ref.getBoundingClientRect(); - this.setState({ width }); + window.requestAnimationFrame(() => { + const { width } = ref.getBoundingClientRect(); + this.setState({ width }); + }); } }; From b6f620b17c963834a3aee2d509dbdbd3fa578464 Mon Sep 17 00:00:00 2001 From: Charles Lee Date: Thu, 3 Jan 2019 13:32:22 +1100 Subject: [PATCH 2/2] add cancelAnimationFrame call to cancel the RAF call on unmount of the component --- src/animated/transitions.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/animated/transitions.js b/src/animated/transitions.js index 4fa304bb42..9b88f3f4d5 100644 --- a/src/animated/transitions.js +++ b/src/animated/transitions.js @@ -62,11 +62,17 @@ type CollapseState = { width: Width }; // finally removing from DOM export class Collapse extends Component { duration = collapseDuration; + rafID: number | null; state = { width: 'auto' }; transition = { exiting: { width: 0, transition: `width ${this.duration}ms ease-out` }, exited: { width: 0 }, }; + componentWillUnmount () { + if (this.rafID) { + window.cancelAnimationFrame(this.rafID); + } + } // width must be calculated; cannot transition from `undefined` to `number` getWidth = (ref: ElementRef<*>) => { @@ -76,10 +82,10 @@ export class Collapse extends Component { call to getBoundingClientRect and setState in order to resolve an edge case around portalling. Certain portalling solutions briefly remove children from the DOM before appending them to the target node. This is to avoid us trying to call getBoundingClientrect - while the Select component is in this state. + while the Select component is in this state. */ // cannot use `offsetWidth` because it is rounded - window.requestAnimationFrame(() => { + this.rafID = window.requestAnimationFrame(() => { const { width } = ref.getBoundingClientRect(); this.setState({ width }); });