diff --git a/src/backend/agent.js b/src/backend/agent.js index d90fa82fc0..78386958a1 100644 --- a/src/backend/agent.js +++ b/src/backend/agent.js @@ -194,9 +194,7 @@ export default class Agent extends EventEmitter { // TODO The chrome.runtime does not currently support transferables; it forces JSON serialization. // The Store has a fallback in place that parses the message as JSON if the type isn't an array. - // Sometimes using transferrables also cause Chrome or Firefox to throw "ArrayBuffer at index 0 is already neutered". - // this._bridge.send('operations', operations, [operations.buffer]); - this._bridge.send('operations', operations); + this._bridge.send('operations', operations, [operations.buffer]); }; _onClick = (event: MouseEvent) => { diff --git a/src/backend/renderer.js b/src/backend/renderer.js index 702f0c852a..ebb56fc9b8 100644 --- a/src/backend/renderer.js +++ b/src/backend/renderer.js @@ -524,6 +524,10 @@ export function attach( } function flushPendingEvents(root: Object): void { + if (pendingOperations.length === 0) { + return; + } + // Identify which renderer this update is coming from. // This enables roots to be mapped to renderers, // Which in turn enables fiber props, states, and hooks to be inspected. diff --git a/src/devtools/views/TreeContext.js b/src/devtools/views/TreeContext.js index a57b0a78f0..62e4b17050 100644 --- a/src/devtools/views/TreeContext.js +++ b/src/devtools/views/TreeContext.js @@ -223,35 +223,41 @@ function reduceSearchState(store: Store, state: State, action: Action): State { }); addedElementIDs.forEach(id => { - const { displayName } = ((store.getElementByID(id): any): Element); + const element = ((store.getElementByID(id): any): Element); - // Add this item to the search results if it matches. - const regExp = createRegExp(searchText); - if (displayName !== null && regExp.test(displayName)) { - const newElementIndex = ((store.getIndexOfElementID( - id - ): any): number); + // It's possible that multiple tree operations will fire before this action has run. + // So it's important to check for elements that may have been added and then removed. + if (element !== null) { + const { displayName } = element; - let foundMatch = false; - for (let index = 0; index < searchResults.length; index++) { - const id = searchResults[index]; - if ( - newElementIndex < - ((store.getIndexOfElementID(id): any): number) - ) { - foundMatch = true; - searchResults = searchResults - .slice(0, index) - .concat(id) - .concat(searchResults.slice(index)); - break; + // Add this item to the search results if it matches. + const regExp = createRegExp(searchText); + if (displayName !== null && regExp.test(displayName)) { + const newElementIndex = ((store.getIndexOfElementID( + id + ): any): number); + + let foundMatch = false; + for (let index = 0; index < searchResults.length; index++) { + const id = searchResults[index]; + if ( + newElementIndex < + ((store.getIndexOfElementID(id): any): number) + ) { + foundMatch = true; + searchResults = searchResults + .slice(0, index) + .concat(id) + .concat(searchResults.slice(index)); + break; + } + } + if (!foundMatch) { + searchResults = searchResults.concat(id); } - } - if (!foundMatch) { - searchResults = searchResults.concat(id); - } - searchIndex = searchIndex === null ? 0 : searchIndex; + searchIndex = searchIndex === null ? 0 : searchIndex; + } } }); } diff --git a/src/types.js b/src/types.js index 3cb12e26fd..2bd576af9b 100644 --- a/src/types.js +++ b/src/types.js @@ -3,7 +3,7 @@ export type Bridge = { addListener(type: string, callback: Function): void, removeListener(type: string, callback: Function): void, - send(type: string, data?: any): void, + send(event: string, payload: any, transferable?: Array): void, }; export type Wall = {|