The approach that suits the SDK's architecture best is to treat each area where your extension inserts content as its own separately mounted component. Following this approach, your extension ends up being a set of React components that are "orchestrated" by the SDK (i.e. they appear at the right time based on what the user is currently doing in Gmail/Inbox). Here's a quick example, using a ComposeView button with its own dropdown:
import React from 'react';
import ReactDOM from 'react-dom';
import ComposeDropdown from './components/ComposeDropdown'; // React Component
InboxSDK.load(2, 'YOUR_APP_ID_HERE').then(({Compose}) => {
Compose.registerComposeViewHandler((composeView) => {
composeView.addButton({
title: "My Nifty Button!",
hasDropdown: true,
onClick(event) {
ReactDOM.render(<ComposeDropdown />, event.dropdown.el);
event.dropdown.once('destroy', () => (
ReactDOM.unmountComponentAtNode(event.dropdown.el)
));
}
});
});
});
The two key points here:
1. In your ComposeView button's onClick() handler, you mount your React component like you would any other using the event.dropdown.el property — this is just an empty HTMLElement inside of the dropdown rendered by the SDK.
2. event.dropdown also provides a 'destroy' event which fires when the dropdown goes away (you can do this in your own code by calling event.dropdown.close() but it can also be triggered by the user clicking outside of your dropdown). When mounting a React component, it is best to register a listener for the 'destroy' event and call ReactDOM.unmountComponentAtNode() to cleanup your component. In the example we use .once() so that the listener will automatically unregister itself after a 'destroy' event fires.
If you're adding something that's not a dropdown (e.g. a ThreadView sidebar) the code looks very similar.
Hope that helps!