Re-added transferrables (after 'shutdown' evt fix) and guard against a tree mutation race
Brian Vaughn committed
Feb 21, 2019 at 14:56 UTC
0c346ceea8650219b1dbb43d7bb0ebbe5732b318
4 files changed
+39
-31
src/backend/agent.js
+1
-3
@@ -194,9 +194,7 @@ export default class Agent extends EventEmitter {
194
195
// TODO The chrome.runtime does not currently support transferables; it forces JSON serialization.
196
// The Store has a fallback in place that parses the message as JSON if the type isn't an array.
197
- // Sometimes using transferrables also cause Chrome or Firefox to throw "ArrayBuffer at index 0 is already neutered".
198
- // this._bridge.send('operations', operations, [operations.buffer]);
199
- this._bridge.send('operations', operations);
197
+ this._bridge.send('operations', operations, [operations.buffer]);
198
};
199
200
_onClick = (event: MouseEvent) => {
src/backend/renderer.js
+4
@@ -524,6 +524,10 @@ export function attach(
524
}
525
526
function flushPendingEvents(root: Object): void {
527
+ if (pendingOperations.length === 0) {
528
+ return;
529
+ }
530
+
531
// Identify which renderer this update is coming from.
532
// This enables roots to be mapped to renderers,
533
// Which in turn enables fiber props, states, and hooks to be inspected.
src/devtools/views/TreeContext.js
+33
-27
@@ -223,35 +223,41 @@ function reduceSearchState(store: Store, state: State, action: Action): State {
223
});
224
225
addedElementIDs.forEach(id => {
226
- const { displayName } = ((store.getElementByID(id): any): Element);
227
-
228
- // Add this item to the search results if it matches.
229
- const regExp = createRegExp(searchText);
230
- if (displayName !== null && regExp.test(displayName)) {
231
- const newElementIndex = ((store.getIndexOfElementID(
232
- id
233
- ): any): number);
234
-
235
- let foundMatch = false;
236
- for (let index = 0; index < searchResults.length; index++) {
237
- const id = searchResults[index];
238
- if (
239
- newElementIndex <
240
- ((store.getIndexOfElementID(id): any): number)
241
- ) {
242
- foundMatch = true;
243
- searchResults = searchResults
244
- .slice(0, index)
245
- .concat(id)
246
- .concat(searchResults.slice(index));
247
- break;
226
+ const element = ((store.getElementByID(id): any): Element);
227
+
228
+ // It's possible that multiple tree operations will fire before this action has run.
229
+ // So it's important to check for elements that may have been added and then removed.
230
+ if (element !== null) {
231
+ const { displayName } = element;
232
+
233
+ // Add this item to the search results if it matches.
234
+ const regExp = createRegExp(searchText);
235
+ if (displayName !== null && regExp.test(displayName)) {
236
+ const newElementIndex = ((store.getIndexOfElementID(
237
+ id
238
+ ): any): number);
239
+
240
+ let foundMatch = false;
241
+ for (let index = 0; index < searchResults.length; index++) {
242
+ const id = searchResults[index];
243
+ if (
244
+ newElementIndex <
245
+ ((store.getIndexOfElementID(id): any): number)
246
+ ) {
247
+ foundMatch = true;
248
+ searchResults = searchResults
249
+ .slice(0, index)
250
+ .concat(id)
251
+ .concat(searchResults.slice(index));
252
+ break;
253
+ }
254
+ }
255
+ if (!foundMatch) {
256
+ searchResults = searchResults.concat(id);
257
}
249
- }
250
- if (!foundMatch) {
251
- searchResults = searchResults.concat(id);
252
- }
258
254
- searchIndex = searchIndex === null ? 0 : searchIndex;
259
+ searchIndex = searchIndex === null ? 0 : searchIndex;
260
+ }
261
}
262
});
263
}
src/types.js
+1
-1
@@ -3,7 +3,7 @@
3
export type Bridge = {
4
addListener(type: string, callback: Function): void,
5
removeListener(type: string, callback: Function): void,
6
- send(type: string, data?: any): void,
6
+ send(event: string, payload: any, transferable?: Array<any>): void,
7
};
8
9
export type Wall = {|