Skip to content

Commit 01921bd

Browse files
authored
Merge pull request #490 from ardeois/fix/unmount-state-issue
fix: state leak when component is unmounted
2 parents d09960e + 0a1e06a commit 01921bd

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

src/Experiment.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
33
import OptimizeContext from "./OptimizeContext";
44

55
class Experiment extends React.Component {
6+
isUnmounted = false;
67
state = {
78
variant: null,
89
};
@@ -48,7 +49,9 @@ class Experiment extends React.Component {
4849
);
4950
const oldHideEnd = window.dataLayer.hide.end;
5051
window.dataLayer.hide.end = () => {
51-
this.updateVariantFromGlobalState();
52+
if (!this.isUnmounted) {
53+
this.updateVariantFromGlobalState();
54+
}
5255
oldHideEnd && oldHideEnd();
5356
};
5457

@@ -82,6 +85,7 @@ class Experiment extends React.Component {
8285

8386
componentWillUnmount() {
8487
clearTimeout(this.updateVariantTimeout);
88+
this.isUnmounted = true;
8589
typeof window !== "undefined" &&
8690
window.gtag &&
8791
window.gtag("event", "optimize.callback", {

test/specs/experiment.spec.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import sinon from "sinon";
44
import { Experiment } from "../../src";
55

66
describe("experiment", () => {
7+
afterEach(() => {
8+
delete window.google_optimize;
9+
delete window.dataLayer;
10+
});
11+
712
it("should require experiment id", () => {
813
expect(() => shallow(<Experiment />)).to.throw();
914
});
@@ -50,5 +55,32 @@ describe("experiment", () => {
5055

5156
expect(wrapper.find(Loader)).to.have.lengthOf(1);
5257
});
58+
59+
it("should update variant after optimize is loaded", () => {
60+
delete window.dataLayer;
61+
const wrapper = shallow(<Experiment id="abc" />);
62+
63+
expect(wrapper.state("variant")).to.be.equal(null);
64+
65+
// Load google optimize
66+
window.google_optimize = { get: sinon.stub().returns("2") };
67+
window.dataLayer.hide.end();
68+
69+
expect(wrapper.state("variant")).to.be.equal("2");
70+
});
71+
72+
it("should not update variant after optimize is loaded if component was unmounted", () => {
73+
delete window.dataLayer;
74+
const wrapper = shallow(<Experiment id="abc" />);
75+
76+
expect(wrapper.state("variant")).to.be.equal(null);
77+
78+
wrapper.unmount();
79+
// Load google optimize
80+
window.google_optimize = { get: sinon.stub().returns("2") };
81+
82+
// If component state is updated while component is unmounted, this call will crash
83+
window.dataLayer.hide.end();
84+
});
5385
});
5486
});

0 commit comments

Comments
 (0)