import React from 'react'; interface Props { /** The View class, which will be instantiated then treated like a Backbone View */ readonly View: BackboneViewConstructor; /** Options to be passed along to the view when constructed */ readonly options: object; } interface BackboneView { remove: () => void; render: () => void; el: HTMLElement; } interface BackboneViewConstructor { new (options: object): BackboneView; } /** * Allows Backbone Views to be rendered inside of React (primarily for the Style Guide) * while we slowly replace the internals of a given Backbone view with React. */ export class BackboneWrapper extends React.Component { protected el: HTMLElement | null = null; protected view: BackboneView | null = null; public componentWillUnmount() { this.teardown(); } public shouldComponentUpdate() { // we're handling all updates manually return false; } public render() { return
; } protected setEl = (element: HTMLDivElement | null) => { this.el = element; this.setup(); } protected setup = () => { const { el } = this; const { View, options } = this.props; if (!el) { return; } this.view = new View(options); this.view.render(); // It's important to let the view create its own root DOM element. This ensures that // its tagName property actually takes effect. el.appendChild(this.view.el); } protected teardown() { if (!this.view) { return; } this.view.remove(); this.view = null; } }