Skip to content

Commit ad3be89

Browse files
committed
use context as global object to fix leak on server side
1 parent ce36e52 commit ad3be89

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

src/libs/ReactI13n.js

+13-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ var debug = debugLib('ReactI13n');
1010
var EventsQueue = require('./EventsQueue');
1111
var I13nNode = require('./I13nNode');
1212
var DEFAULT_HANDLER_TIMEOUT = 1000;
13-
var GLOBAL_OBJECT = ('client' === ENVIRONMENT) ? window : global;
1413
var ENVIRONMENT = (typeof window !== 'undefined') ? 'client' : 'server';
1514

1615
// export the debug lib in client side
@@ -26,6 +25,7 @@ if ('client' === ENVIRONMENT) {
2625
* @param {Object} options.rootModelData model data of root i13n node
2726
* @param {Object} options.i13nNodeClass the i13nNode class, you can inherit it with your own functionalities
2827
* @param {String} options.scrollableContainerId id of the scrollable element that your components
28+
* @param {String} options.context context object
2929
* reside within. Normally, you won't need to provide a value for this. This is only to
3030
* support viewport checking when your components are contained within a scrollable element.
3131
* Currently, only elements that fill the viewport are supported.
@@ -42,19 +42,21 @@ var ReactI13n = function ReactI13n (options) {
4242
this._rootModelData = options.rootModelData || {};
4343
this._handlerTimeout = options.handlerTimeout || DEFAULT_HANDLER_TIMEOUT;
4444
this._scrollableContainerId = options.scrollableContainerId || undefined;
45+
this._context = options.context;
4546

4647
// set itself to the global object so that we can get it anywhere by the static function getInstance
47-
GLOBAL_OBJECT.reactI13n = this;
48+
this._context.reactI13n = this;
4849
};
4950

5051
/**
5152
* Get ReactI13n Instance
5253
* @method getInstance
54+
* @param {Object} context context object
5355
* @return the ReactI13n instance
5456
* @static
5557
*/
56-
ReactI13n.getInstance = function getInstance () {
57-
return GLOBAL_OBJECT.reactI13n;
58+
ReactI13n.getInstance = function getInstance (context) {
59+
return context.reactI13n;;
5860
};
5961

6062
/**
@@ -63,11 +65,14 @@ ReactI13n.getInstance = function getInstance () {
6365
*/
6466
ReactI13n.prototype.createRootI13nNode = function createRootI13nNode () {
6567
var I13nNodeClass = this.getI13nNodeClass();
66-
GLOBAL_OBJECT.rootI13nNode = new I13nNodeClass(null, this._rootModelData, false);
68+
if (this._context.rootI13nNode) {
69+
return this._context.rootI13nNode;
70+
}
71+
this._context.rootI13nNode = new I13nNodeClass(null, this._rootModelData, false);
6772
if ('client' === ENVIRONMENT) {
68-
GLOBAL_OBJECT.rootI13nNode.setDOMNode(document.body);
73+
this._context.rootI13nNode.setDOMNode(document.body);
6974
}
70-
return GLOBAL_OBJECT.rootI13nNode;
75+
return this._context.rootI13nNode;
7176
};
7277

7378
/**
@@ -191,7 +196,7 @@ ReactI13n.prototype.getScrollableContainerDOMNode = function getScrollableContai
191196
* @return {Object} root react i13n node
192197
*/
193198
ReactI13n.prototype.getRootI13nNode = function getRootI13nNode () {
194-
return GLOBAL_OBJECT.rootI13nNode;
199+
return this._context.rootI13nNode;
195200
};
196201

197202
/**

src/mixins/I13nUtils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ var I13nUtils = {
7676
* @return {Object} react i13n instance
7777
*/
7878
_getReactI13n: function () {
79-
return ReactI13n.getInstance();
79+
return ReactI13n.getInstance(this.context);
8080
},
8181

8282
/**

src/utils/setupI13n.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ module.exports = function setupI13n (Component, options, plugins) {
2525
var RootI13nComponent;
2626
var componentName = Component.displayName || Component.name;
2727

28-
var reactI13n = new ReactI13n(options);
29-
plugins.forEach(function setPlugin(plugin) {
30-
reactI13n.plug(plugin);
31-
});
32-
3328
RootI13nComponent = React.createClass({
3429

3530
mixins: [I13nUtils],
@@ -43,7 +38,11 @@ module.exports = function setupI13n (Component, options, plugins) {
4338
* @method componentWillMount
4439
*/
4540
componentWillMount: function () {
46-
var reactI13n = ReactI13n.getInstance();
41+
var reactI13n = ReactI13n.getInstance(this.context);
42+
var reactI13n = new ReactI13n(options);
43+
plugins.forEach(function setPlugin(plugin) {
44+
reactI13n.plug(plugin);
45+
});
4746
reactI13n.createRootI13nNode();
4847
},
4948

tests/unit/libs/ReactI13n.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,23 @@
88

99
var expect = require('expect.js');
1010
var ReactI13n = require('../../../../dist/libs/ReactI13n');
11+
var mockContext = {};
1112

1213
describe('ReactI13n', function () {
1314

1415
it('should be created correctly', function () {
1516
var reactI13n = new ReactI13n({
17+
context: mockContext,
1618
isViewportEnabled: true
1719
});
18-
expect(ReactI13n.getInstance()).to.eql(reactI13n); // static function should be able to get the instance we created
20+
expect(ReactI13n.getInstance(mockContext)).to.eql(reactI13n);
21+
// static function should be able to get the instance we created
1922
expect(reactI13n.isViewportEnabled()).to.eql(true);
2023
});
2124

2225
it('should be able to update options', function () {
2326
var reactI13n = new ReactI13n({
27+
context: mockContext,
2428
isViewportEnabled: true
2529
});
2630
expect(reactI13n.isViewportEnabled()).to.eql(true);
@@ -41,6 +45,7 @@ describe('ReactI13n', function () {
4145
return rootModelData;
4246
}
4347
var reactI13n = new ReactI13n({
48+
context: mockContext,
4449
rootModelData: rootModelData,
4550
i13nNodeClass: mockReactI13nClass
4651
});
@@ -68,7 +73,9 @@ describe('ReactI13n', function () {
6873
}
6974
}
7075
};
71-
var reactI13n = new ReactI13n({});
76+
var reactI13n = new ReactI13n({
77+
context: mockContext,
78+
});
7279
reactI13n.plug(mockPlugin1);
7380
reactI13n.plug(mockPlugin2);
7481
// two plugin should be executed correctly then call the custom callback
@@ -93,7 +100,9 @@ describe('ReactI13n', function () {
93100
foo: 'bar'
94101
};
95102

96-
var reactI13n = new ReactI13n({});
103+
var reactI13n = new ReactI13n({
104+
context: mockContext,
105+
});
97106
reactI13n.plug(mockPlugin1);
98107
reactI13n.execute('click', payload, function () {
99108
// should only have one attribute as 'foo', which means payload is not modified inside reactI13n.execute
@@ -112,7 +121,9 @@ describe('ReactI13n', function () {
112121
}
113122
};
114123

115-
var reactI13n = new ReactI13n({});
124+
var reactI13n = new ReactI13n({
125+
context: mockContext,
126+
});
116127
reactI13n.plug(mockPlugin1);
117128
// two plugin should be executed correctly then call the custom callback
118129
reactI13n.execute('click', {}, function () {
@@ -124,6 +135,7 @@ describe('ReactI13n', function () {
124135

125136
it('should be able to set a scrollableContainerId', function () {
126137
var reactI13n = new ReactI13n({
138+
context: mockContext,
127139
scrollableContainerId: 'scrollable-test'
128140
});
129141

@@ -132,6 +144,7 @@ describe('ReactI13n', function () {
132144

133145
it('should have an undefined scrollableContainerDOMNode if the scrollableContainerId is undefined', function () {
134146
var reactI13n = new ReactI13n({
147+
context: mockContext,
135148
isViewportEnabled: true
136149
});
137150

0 commit comments

Comments
 (0)