@samitouri / QOS-React / commits / 755724a24c

Implement event-specific pooling for SyntheticEvent (#10237)

* Remove PooledClass from FallbackCompositionState The only module that uses FallbackCompositonState is BeforeInputEventPlugin. The way its structured means there can only be a single instance of FallbackCompositionState at any given time (stored in a local variable at the top-level) so we don't really need pooling here at all. Instead, a single object is now stored in FallbackCompositionState, and access (initializing, reseting, getting data) is gaurded by the exported helper object. * Use new FallbackCompositionState API in BeforeInputEventPlugin * Implement event-specific pooling in SyntheticEvent * Remove PooledClass from TopLevelCallbackBookKeeping * Update results.json * Add pooled event test fixtures (#1) * Fix fixture lint

Brandon Dail committed Aug 4, 2017 at 12:24 UTC 755724a24c4743b5507590e512cdf2f24d9b8435
12 files changed +368 -159
fixtures/dom/src/components/Header.js
+1
@@ -61,6 +61,7 @@ class Header extends React.Component {
61 <option value="/buttons">Buttons</option>
62 <option value="/date-inputs">Date Inputs</option>
63 <option value="/error-handling">Error Handling</option>
64 + <option value="/event-pooling">Event Pooling</option>
65 </select>
66 </label>
67 <label htmlFor="react_version">
fixtures/dom/src/components/fixtures/event-pooling/hit-box.js new
+38
@@ -0,0 +1,38 @@
1 +const React = window.React;
2 +
3 +class HitBox extends React.Component {
4 + state = {
5 + x: 0,
6 + y: 0,
7 + };
8 +
9 + static defaultProps = {
10 + onMouseMove: n => n,
11 + };
12 +
13 + onMove = event => {
14 + this.setState({x: event.clientX, y: event.clientY});
15 + this.props.onMouseMove(event);
16 + };
17 +
18 + render() {
19 + const {x, y} = this.state;
20 +
21 + const boxStyle = {
22 + padding: '10px 20px',
23 + border: '1px solid #d9d9d9',
24 + margin: '10px 0 20px',
25 + };
26 +
27 + return (
28 + <div onMouseMove={this.onMove} style={boxStyle}>
29 + <p>Trace your mouse over this box.</p>
30 + <p>
31 + Last movement: {x},{y}
32 + </p>
33 + </div>
34 + );
35 + }
36 +}
37 +
38 +export default HitBox;
fixtures/dom/src/components/fixtures/event-pooling/index.js new
+18
@@ -0,0 +1,18 @@
1 +import FixtureSet from '../../FixtureSet';
2 +import MouseMove from './mouse-move';
3 +import Persistence from './persistence';
4 +
5 +const React = window.React;
6 +
7 +class EventPooling extends React.Component {
8 + render() {
9 + return (
10 + <FixtureSet title="Event Pooling" description="">
11 + <MouseMove />
12 + <Persistence />
13 + </FixtureSet>
14 + );
15 + }
16 +}
17 +
18 +export default EventPooling;
fixtures/dom/src/components/fixtures/event-pooling/mouse-move.js new
+51
@@ -0,0 +1,51 @@
1 +import TestCase from '../../TestCase';
2 +import HitBox from './hit-box';
3 +
4 +const React = window.React;
5 +
6 +class MouseMove extends React.Component {
7 + state = {
8 + events: [],
9 + };
10 +
11 + checkEvent = event => {
12 + let {events} = this.state;
13 +
14 + if (event.type === 'mousemove' && events.indexOf(event) === -1) {
15 + this.setState({events: events.concat(event)});
16 + }
17 + };
18 +
19 + render() {
20 + const {events} = this.state;
21 +
22 + return (
23 + <TestCase title="Mouse Move" description="">
24 + <TestCase.Steps>
25 + <li>Mouse over the box below</li>
26 + </TestCase.Steps>
27 +
28 + <TestCase.ExpectedResult>
29 + Mousemove should share the same instance of the event between
30 + dispatches.
31 + </TestCase.ExpectedResult>
32 +
33 + <HitBox onMouseMove={this.checkEvent} />
34 +
35 + <p>
36 + Was the event pooled?{' '}
37 + <b>
38 + {events.length ? events.length <= 1 ? 'Yes' : 'No' : 'Unsure'}
39 + {' '}
40 + (
41 + {events.length}
42 + {' '}
43 + events)
44 + </b>
45 + </p>
46 + </TestCase>
47 + );
48 + }
49 +}
50 +
51 +export default MouseMove;
fixtures/dom/src/components/fixtures/event-pooling/persistence.js new
+65
@@ -0,0 +1,65 @@
1 +import TestCase from '../../TestCase';
2 +import HitBox from './hit-box';
3 +
4 +const React = window.React;
5 +
6 +class Persistence extends React.Component {
7 + state = {
8 + persisted: 0,
9 + pooled: [],
10 + };
11 +
12 + addPersisted = event => {
13 + let {persisted, pooled} = this.state;
14 +
15 + event.persist();
16 +
17 + if (event.type === 'mousemove') {
18 + this.setState({
19 + persisted: persisted + 1,
20 + pooled: pooled.filter(e => e !== event),
21 + });
22 + }
23 + };
24 +
25 + addPooled = event => {
26 + let {pooled} = this.state;
27 +
28 + if (event.type === 'mousemove' && pooled.indexOf(event) === -1) {
29 + this.setState({pooled: pooled.concat(event)});
30 + }
31 + };
32 +
33 + render() {
34 + const {pooled, persisted} = this.state;
35 +
36 + return (
37 + <TestCase title="Persistence" description="">
38 + <TestCase.Steps>
39 + <li>Mouse over the pooled event box</li>
40 + <li>Mouse over the persisted event box</li>
41 + </TestCase.Steps>
42 +
43 + <TestCase.ExpectedResult>
44 + The pool size should not increase above 1, but reduce to 0 when hovering over the persisted region.
45 + </TestCase.ExpectedResult>
46 +
47 + <h2>Add Pooled Event:</h2>
48 + <HitBox onMouseMove={this.addPooled} />
49 +
50 + <h2>Add Persisted Event:</h2>
51 + <HitBox onMouseMove={this.addPersisted} />
52 +
53 + <p>
54 + Pool size: {pooled.length}
55 + </p>
56 +
57 + <p>
58 + Persisted size: {persisted}
59 + </p>
60 + </TestCase>
61 + );
62 + }
63 +}
64 +
65 +export default Persistence;
fixtures/dom/src/components/fixtures/index.js
+3
@@ -8,6 +8,7 @@ import PasswordInputFixtures from './password-inputs';
8 import ButtonFixtures from './buttons';
9 import DateInputFixtures from './date-inputs';
10 import ErrorHandling from './error-handling';
11 +import EventPooling from './event-pooling';
12
13 const React = window.React;
14
@@ -37,6 +38,8 @@ function FixturesPage() {
38 return <DateInputFixtures />;
39 case '/error-handling':
40 return <ErrorHandling />;
41 + case '/event-pooling':
42 + return <EventPooling />;
43 default:
44 return <p>Please select a test fixture.</p>;
45 }
scripts/rollup/results.json
+67 -67
@@ -1,16 +1,16 @@
1 {
2 "bundleSizes": {
3 "react.development.js (UMD_DEV)": {
4 - "size": 65960,
5 - "gzip": 16789
4 + "size": 65980,
5 + "gzip": 16788
6 },
7 "react.production.min.js (UMD_PROD)": {
8 "size": 6734,
9 "gzip": 2757
10 },
11 "react.development.js (NODE_DEV)": {
12 - "size": 56282,
13 - "gzip": 14446
12 + "size": 56302,
13 + "gzip": 14443
14 },
15 "react.production.min.js (NODE_PROD)": {
16 "size": 5596,
@@ -25,76 +25,76 @@
25 "gzip": 6703
26 },
27 "react-dom.development.js (UMD_DEV)": {
28 - "size": 635877,
29 - "gzip": 145302
28 + "size": 634973,
29 + "gzip": 144789
30 },
31 "react-dom.production.min.js (UMD_PROD)": {
32 - "size": 120935,
33 - "gzip": 38567
32 + "size": 119734,
33 + "gzip": 38187
34 },
35 "react-dom.development.js (NODE_DEV)": {
36 - "size": 595290,
37 - "gzip": 135669
36 + "size": 594382,
37 + "gzip": 135201
38 },
39 "react-dom.production.min.js (NODE_PROD)": {
40 - "size": 117857,
41 - "gzip": 37500
40 + "size": 116650,
41 + "gzip": 37146
42 },
43 "ReactDOMFiber-dev.js (FB_DEV)": {
44 - "size": 592102,
45 - "gzip": 135156
44 + "size": 591210,
45 + "gzip": 134689
46 },
47 "ReactDOMFiber-prod.js (FB_PROD)": {
48 - "size": 426047,
49 - "gzip": 95491
48 + "size": 424757,
49 + "gzip": 95144
50 },
51 "react-dom-test-utils.development.js (NODE_DEV)": {
52 - "size": 55584,
53 - "gzip": 14051
52 + "size": 53568,
53 + "gzip": 13486
54 },
55 "ReactTestUtils-dev.js (FB_DEV)": {
56 - "size": 55374,
57 - "gzip": 14012
56 + "size": 53378,
57 + "gzip": 13448
58 },
59 "react-dom-unstable-native-dependencies.development.js (UMD_DEV)": {
60 - "size": 90271,
61 - "gzip": 22897
60 + "size": 88255,
61 + "gzip": 22338
62 },
63 "react-dom-unstable-native-dependencies.production.min.js (UMD_PROD)": {
64 - "size": 18338,
65 - "gzip": 5956
64 + "size": 18178,
65 + "gzip": 5939
66 },
67 "react-dom-unstable-native-dependencies.development.js (NODE_DEV)": {
68 - "size": 83719,
69 - "gzip": 20982
68 + "size": 81703,
69 + "gzip": 20376
70 },
71 "react-dom-unstable-native-dependencies.production.min.js (NODE_PROD)": {
72 - "size": 16978,
73 - "gzip": 5429
72 + "size": 16448,
73 + "gzip": 5300
74 },
75 "ReactDOMUnstableNativeDependencies-dev.js (FB_DEV)": {
76 - "size": 83418,
77 - "gzip": 20945
76 + "size": 81422,
77 + "gzip": 20340
78 },
79 "ReactDOMUnstableNativeDependencies-prod.js (FB_PROD)": {
80 - "size": 67022,
81 - "gzip": 15921
80 + "size": 66066,
81 + "gzip": 15736
82 },
83 "react-dom-server.browser.development.js (UMD_DEV)": {
84 - "size": 123103,
85 - "gzip": 31119
84 + "size": 123129,
85 + "gzip": 31128
86 },
87 "react-dom-server.browser.production.min.js (UMD_PROD)": {
88 - "size": 22069,
89 - "gzip": 8359
88 + "size": 21353,
89 + "gzip": 8162
90 },
91 "react-dom-server.browser.development.js (NODE_DEV)": {
92 - "size": 92259,
92 + "size": 92285,
93 "gzip": 23724
94 },
95 "react-dom-server.browser.production.min.js (NODE_PROD)": {
96 - "size": 20470,
97 - "gzip": 7751
96 + "size": 20116,
97 + "gzip": 7657
98 },
99 "ReactDOMServer-dev.js (FB_DEV)": {
100 "size": 91498,
@@ -105,60 +105,60 @@
105 "gzip": 13944
106 },
107 "react-dom-server.node.development.js (NODE_DEV)": {
108 - "size": 94946,
109 - "gzip": 24289
108 + "size": 95018,
109 + "gzip": 24291
110 },
111 "react-dom-server.node.production.min.js (NODE_PROD)": {
112 - "size": 21375,
113 - "gzip": 8033
112 + "size": 21207,
113 + "gzip": 8013
114 },
115 "react-art.development.js (UMD_DEV)": {
116 - "size": 372653,
117 - "gzip": 82680
116 + "size": 373741,
117 + "gzip": 82785
118 },
119 "react-art.production.min.js (UMD_PROD)": {
120 - "size": 93748,
121 - "gzip": 29003
120 + "size": 93224,
121 + "gzip": 28829
122 },
123 "react-art.development.js (NODE_DEV)": {
124 - "size": 294040,
125 - "gzip": 62650
124 + "size": 295128,
125 + "gzip": 62771
126 },
127 "react-art.production.min.js (NODE_PROD)": {
128 - "size": 55318,
129 - "gzip": 17053
128 + "size": 55164,
129 + "gzip": 16977
130 },
131 "ReactARTFiber-dev.js (FB_DEV)": {
132 - "size": 293027,
133 - "gzip": 62742
132 + "size": 294057,
133 + "gzip": 62846
134 },
135 "ReactARTFiber-prod.js (FB_PROD)": {
136 "size": 219827,
137 "gzip": 45605
138 },
139 "ReactNativeStack-dev.js (RN_DEV)": {
140 - "size": 200977,
141 - "gzip": 37381
140 + "size": 201902,
141 + "gzip": 37570
142 },
143 "ReactNativeStack-prod.js (RN_PROD)": {
144 - "size": 137361,
145 - "gzip": 26398
144 + "size": 138226,
145 + "gzip": 26573
146 },
147 "ReactNativeFiber-dev.js (RN_DEV)": {
148 - "size": 307751,
149 - "gzip": 53404
148 + "size": 307333,
149 + "gzip": 53302
150 },
151 "ReactNativeFiber-prod.js (RN_PROD)": {
152 - "size": 224000,
153 - "gzip": 38939
152 + "size": 222948,
153 + "gzip": 38742
154 },
155 "react-test-renderer.development.js (NODE_DEV)": {
156 - "size": 291878,
157 - "gzip": 61552
156 + "size": 292928,
157 + "gzip": 61669
158 },
159 "ReactTestRendererFiber-dev.js (FB_DEV)": {
160 - "size": 290826,
161 - "gzip": 61649
160 + "size": 291856,
161 + "gzip": 61755
162 },
163 "react-test-renderer-shallow.development.js (NODE_DEV)": {
164 "size": 9812,
@@ -169,8 +169,8 @@
169 "gzip": 2439
170 },
171 "react-noop-renderer.development.js (NODE_DEV)": {
172 - "size": 285805,
173 - "gzip": 59966
172 + "size": 286835,
173 + "gzip": 60082
174 }
175 }
176 }
\ No newline at end of file
src/renderers/dom/shared/ReactDOMEventListener.js
+29 -20
@@ -12,7 +12,6 @@
12 'use strict';
13
14 var EventListener = require('fbjs/lib/EventListener');
15 -var PooledClass = require('PooledClass');
15 var ReactDOMComponentTree = require('ReactDOMComponentTree');
16 var ReactFiberTreeReflection = require('ReactFiberTreeReflection');
17 var ReactGenericBatching = require('ReactGenericBatching');
@@ -22,6 +21,9 @@ var getEventTarget = require('getEventTarget');
21
22 var {HostRoot} = ReactTypeOfWork;
23
24 +var CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
25 +var callbackBookkeepingPool = [];
26 +
27 /**
28 * Find the deepest React component completely containing the root of the
29 * passed-in instance (for use when entire React trees are nested within each
@@ -50,24 +52,31 @@ function findRootContainerNode(inst) {
52 }
53
54 // Used to store ancestor hierarchy in top level callback
53 -function TopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) {
54 - this.topLevelType = topLevelType;
55 - this.nativeEvent = nativeEvent;
56 - this.targetInst = targetInst;
57 - this.ancestors = [];
55 +function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) {
56 + if (callbackBookkeepingPool.length) {
57 + const instance = callbackBookkeepingPool.pop();
58 + instance.topLevelType = topLevelType;
59 + instance.nativeEvent = nativeEvent;
60 + instance.targetInst = targetInst;
61 + return instance;
62 + }
63 + return {
64 + topLevelType,
65 + nativeEvent,
66 + targetInst,
67 + ancestors: [],
68 + };
69 +}
70 +
71 +function releaseTopLevelCallbackBookKeeping(instance) {
72 + instance.topLevelType = null;
73 + instance.nativeEvent = null;
74 + instance.targetInst = null;
75 + instance.ancestors.length = 0;
76 + if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) {
77 + callbackBookkeepingPool.push(instance);
78 + }
79 }
59 -Object.assign(TopLevelCallbackBookKeeping.prototype, {
60 - destructor: function() {
61 - this.topLevelType = null;
62 - this.nativeEvent = null;
63 - this.targetInst = null;
64 - this.ancestors.length = 0;
65 - },
66 -});
67 -PooledClass.addPoolingTo(
68 - TopLevelCallbackBookKeeping,
69 - PooledClass.threeArgumentPooler,
70 -);
80
81 function handleTopLevelImpl(bookKeeping) {
82 var targetInst = bookKeeping.targetInst;
@@ -180,7 +189,7 @@ var ReactDOMEventListener = {
189 targetInst = null;
190 }
191
183 - var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
192 + var bookKeeping = getTopLevelCallbackBookKeeping(
193 topLevelType,
194 nativeEvent,
195 targetInst,
@@ -191,7 +200,7 @@ var ReactDOMEventListener = {
200 // `preventDefault`.
201 ReactGenericBatching.batchedUpdates(handleTopLevelImpl, bookKeeping);
202 } finally {
194 - TopLevelCallbackBookKeeping.release(bookKeeping);
203 + releaseTopLevelCallbackBookKeeping(bookKeeping);
204 }
205 },
206 };
src/renderers/dom/shared/eventPlugins/BeforeInputEventPlugin.js
+11 -13
@@ -209,8 +209,8 @@ function getDataFromCustomEvent(nativeEvent) {
209 return null;
210 }
211
212 -// Track the current IME composition fallback object, if any.
213 -var currentComposition = null;
212 +// Track the current IME composition status, if any.
213 +var isComposing = false;
214
215 /**
216 * @return {?object} A SyntheticCompositionEvent.
@@ -226,7 +226,7 @@ function extractCompositionEvent(
226
227 if (canUseCompositionEvent) {
228 eventType = getCompositionEventType(topLevelType);
229 - } else if (!currentComposition) {
229 + } else if (!isComposing) {
230 if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
231 eventType = eventTypes.compositionStart;
232 }
@@ -241,13 +241,11 @@ function extractCompositionEvent(
241 if (useFallbackCompositionData) {
242 // The current composition is stored statically and must not be
243 // overwritten while composition continues.
244 - if (!currentComposition && eventType === eventTypes.compositionStart) {
245 - currentComposition = FallbackCompositionState.getPooled(
246 - nativeEventTarget,
247 - );
244 + if (!isComposing && eventType === eventTypes.compositionStart) {
245 + isComposing = FallbackCompositionState.initialize(nativeEventTarget);
246 } else if (eventType === eventTypes.compositionEnd) {
249 - if (currentComposition) {
250 - fallbackData = currentComposition.getData();
247 + if (isComposing) {
248 + fallbackData = FallbackCompositionState.getData();
249 }
250 }
251 }
@@ -338,15 +336,15 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
336 // try to extract the composed characters from the fallback object.
337 // If composition event is available, we extract a string only at
338 // compositionevent, otherwise extract it at fallback events.
341 - if (currentComposition) {
339 + if (isComposing) {
340 if (
341 topLevelType === 'topCompositionEnd' ||
342 (!canUseCompositionEvent &&
343 isFallbackCompositionEnd(topLevelType, nativeEvent))
344 ) {
347 - var chars = currentComposition.getData();
348 - FallbackCompositionState.release(currentComposition);
349 - currentComposition = null;
345 + var chars = FallbackCompositionState.getData();
346 + FallbackCompositionState.reset();
347 + isComposing = false;
348 return chars;
349 }
350 return null;
src/renderers/dom/shared/eventPlugins/FallbackCompositionState.js
+30 -42
@@ -11,62 +11,46 @@
11
12 'use strict';
13
14 -var PooledClass = require('PooledClass');
15 -
14 var getTextContentAccessor = require('getTextContentAccessor');
15
16 /**
19 - * This helper class stores information about text content of a target node,
17 + * This helper object stores information about text content of a target node,
18 * allowing comparison of content before and after a given event.
19 *
20 * Identify the node where selection currently begins, then observe
21 * both its text content and its current position in the DOM. Since the
22 * browser may natively replace the target node during composition, we can
23 * use its position to find its replacement.
24 + *
25 *
27 - * @param {DOMEventTarget} root
26 */
29 -function FallbackCompositionState(root) {
30 - this._root = root;
31 - this._startText = this.getText();
32 - this._fallbackText = null;
33 -}
27 +var compositionState = {
28 + _root: null,
29 + _startText: null,
30 + _fallbackText: null,
31 +};
32
35 -Object.assign(FallbackCompositionState.prototype, {
36 - destructor: function() {
37 - this._root = null;
38 - this._startText = null;
39 - this._fallbackText = null;
33 +var FallbackCompositionState = {
34 + initialize(nativeEventTarget) {
35 + compositionState._root = nativeEventTarget;
36 + compositionState._startText = FallbackCompositionState.getText();
37 + return true;
38 },
41 -
42 - /**
43 - * Get current text of input.
44 - *
45 - * @return {string}
46 - */
47 - getText: function() {
48 - if ('value' in this._root) {
49 - return this._root.value;
50 - }
51 - return this._root[getTextContentAccessor()];
39 + reset() {
40 + compositionState._root = null;
41 + compositionState._startText = null;
42 + compositionState._fallbackText = null;
43 },
53 -
54 - /**
55 - * Determine the differing substring between the initially stored
56 - * text content and the current content.
57 - *
58 - * @return {string}
59 - */
60 - getData: function() {
61 - if (this._fallbackText) {
62 - return this._fallbackText;
44 + getData() {
45 + if (compositionState._fallbackText) {
46 + return compositionState._fallbackText;
47 }
48
49 var start;
66 - var startValue = this._startText;
50 + var startValue = compositionState._startText;
51 var startLength = startValue.length;
52 var end;
69 - var endValue = this.getText();
53 + var endValue = FallbackCompositionState.getText();
54 var endLength = endValue.length;
55
56 for (start = 0; start < startLength; start++) {
@@ -83,11 +67,15 @@ Object.assign(FallbackCompositionState.prototype, {
67 }
68
69 var sliceTail = end > 1 ? 1 - end : undefined;
86 - this._fallbackText = endValue.slice(start, sliceTail);
87 - return this._fallbackText;
70 + compositionState._fallbackText = endValue.slice(start, sliceTail);
71 + return compositionState._fallbackText;
72 },
89 -});
90 -
91 -PooledClass.addPoolingTo(FallbackCompositionState);
73 + getText() {
74 + if ('value' in compositionState._root) {
75 + return compositionState._root.value;
76 + }
77 + return compositionState._root[getTextContentAccessor()];
78 + },
79 +};
80
81 module.exports = FallbackCompositionState;
src/renderers/dom/shared/eventPlugins/__tests__/FallbackCompositionState-test.js
+12 -12
@@ -43,24 +43,24 @@ describe('FallbackCompositionState', () => {
43
44 function assertExtractedData(modifiedValue, expectedData) {
45 var input = getInput();
46 - var composition = FallbackCompositionState.getPooled(input);
46 + FallbackCompositionState.initialize(input);
47 input.value = modifiedValue;
48 - expect(composition.getData()).toBe(expectedData);
49 - FallbackCompositionState.release(composition);
48 + expect(FallbackCompositionState.getData()).toBe(expectedData);
49 + FallbackCompositionState.reset();
50 }
51
52 it('extracts value via `getText()`', () => {
53 - var composition = FallbackCompositionState.getPooled(getInput());
54 - expect(composition.getText()).toBe(TEXT);
55 - FallbackCompositionState.release(composition);
53 + FallbackCompositionState.initialize(getInput());
54 + expect(FallbackCompositionState.getText()).toBe(TEXT);
55 + FallbackCompositionState.reset();
56
57 - composition = FallbackCompositionState.getPooled(getTextarea());
58 - expect(composition.getText()).toBe(TEXT);
59 - FallbackCompositionState.release(composition);
57 + FallbackCompositionState.initialize(getTextarea());
58 + expect(FallbackCompositionState.getText()).toBe(TEXT);
59 + FallbackCompositionState.reset();
60
61 - composition = FallbackCompositionState.getPooled(getContentEditable());
62 - expect(composition.getText()).toBe(TEXT);
63 - FallbackCompositionState.release(composition);
61 + FallbackCompositionState.initialize(getContentEditable());
62 + expect(FallbackCompositionState.getText()).toBe(TEXT);
63 + FallbackCompositionState.reset();
64 });
65
66 describe('Extract fallback data inserted at collapsed cursor', () => {
src/renderers/shared/shared/event/SyntheticEvent.js
+43 -5
@@ -13,12 +13,12 @@
13
14 'use strict';
15
16 -var PooledClass = require('PooledClass');
17 -
16 var emptyFunction = require('fbjs/lib/emptyFunction');
17 +var invariant = require('fbjs/lib/invariant');
18
19 var didWarnForAddedNewProperty = false;
20 var isProxySupported = typeof Proxy === 'function';
21 +var EVENT_POOL_SIZE = 10;
22
23 if (__DEV__) {
24 var warning = require('fbjs/lib/warning');
@@ -232,8 +232,7 @@ SyntheticEvent.augmentClass = function(Class, Interface) {
232
233 Class.Interface = Object.assign({}, Super.Interface, Interface);
234 Class.augmentClass = Super.augmentClass;
235 -
236 - PooledClass.addPoolingTo(Class, PooledClass.fourArgumentPooler);
235 + addEventPoolingTo(Class);
236 };
237
238 /** Proxying after everything set on SyntheticEvent
@@ -274,7 +273,7 @@ if (__DEV__) {
273 }
274 }
275
277 -PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler);
276 +addEventPoolingTo(SyntheticEvent);
277
278 module.exports = SyntheticEvent;
279
@@ -322,3 +321,42 @@ function getPooledWarningPropertyDefinition(propName, getVal) {
321 );
322 }
323 }
324 +
325 +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) {
326 + const EventConstructor = this;
327 + if (EventConstructor.eventPool.length) {
328 + const instance = EventConstructor.eventPool.pop();
329 + EventConstructor.call(
330 + instance,
331 + dispatchConfig,
332 + targetInst,
333 + nativeEvent,
334 + nativeInst,
335 + );
336 + return instance;
337 + }
338 + return new EventConstructor(
339 + dispatchConfig,
340 + targetInst,
341 + nativeEvent,
342 + nativeInst,
343 + );
344 +}
345 +
346 +function releasePooledEvent(event) {
347 + var EventConstructor = this;
348 + invariant(
349 + event instanceof EventConstructor,
350 + 'Trying to release an event instance into a pool of a different type.',
351 + );
352 + event.destructor();
353 + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
354 + EventConstructor.eventPool.push(event);
355 + }
356 +}
357 +
358 +function addEventPoolingTo(EventConstructor) {
359 + EventConstructor.eventPool = [];
360 + EventConstructor.getPooled = getPooledEvent;
361 + EventConstructor.release = releasePooledEvent;
362 +}