使用Widgets运行PhosphorJS DockerPanel INSIDE a React组件

时间:2017-08-14 23:38:24

标签: javascript reactjs jsx

我有一个反应应用程序,在其中一个组件中我想渲染一个Phosphor桌面(http://phosphorjs.github.io)。

Web源提供了相反的方法,在Phosphor Widget中运行React组件,但是我需要在反应组件中包含带有小部件的Phosphor桌面。不确定如何去做。

这是我的第一次尝试:

import React, { Component } from 'react';
import './App.css';

import { DockPanel } from 'phosphor-dockpanel';
import { Message } from 'phosphor-messaging';
import { TabPanel } from 'phosphor-tabs';
import { ResizeMessage, Widget } from 'phosphor-widget';


class MyWidget extends Widget {

  static createNode() {
    console.log('widget:createNode');
    var node = document.createElement('div');
    var app = document.createElement('div');
    app.className = 'todoapp';
    node.appendChild(app);
    return node;
  }

  constructor(model) {
    super();
    this.addClass('TodoWidget');
    this._model = model;
    console.log('widget:constructor');
  }

  get model() {
    console.log('widget:getModel');    
    return this._model;
  }

  onAfterAttach(msg) {
    console.log('onAfterAttach');
    //this._model.subscribe(() => this.update());
    this.update();
  }

  onUpdateRequest(msg) {
    console.log('widget:onUpdateRequest');    
    var data = { model: this._model };
    var host = this.node.firstChild;
    //React.render(React.createElement(app.TodoApp, data), host);
  }
}


class ReactDockPanel extends Component {
  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.panel = new DockPanel();
    this.panel.id = this.props.id;

    this.widget = new MyWidget();
    this.panel.insertLeft(this.widget);
  }

  componentDidMount() {
    this.panel.attach(this.node);
  }

  render() {
    return (
      <div ref={el=>this.node=el}>
      </div>  
    );
  }    
}

class App extends Component {

  render() {
    return (
      <ReactDockPanel id='main'>
      </ReactDockPanel>
    );
  }
}

export default App;

我不知道如何替换React.render(React.createElement(app.TodoApp,data),host); Phosphor docs仅供参考,但不适用于学习,因此我将使用他们唯一的示例代码。

理想情况下,我希望能够像这样呈现:

<ReactDockPanel id='mydesktop'>
  <SomeWidget insert='left' />
  <SomeOtherWidget insert='right' />
</ReactDockPanel>

不确定是否可以完成。

1 个答案:

答案 0 :(得分:0)

我能够使用React门户进行类似的工作。就我而言,我试图呈现React Component子代而不是Widget子代,但希望它仍然会有所帮助。我使用的步骤是

1)在我的外部React组件的初始渲染中,使用ref获取对该元素的引用。

2)在componentDidMount中,创建一个新的DockPanel并将其附加到该元素。然后,循环浏览所需的小部件,并a)将每个小部件添加到DockPanel中,然后b)建立一个节点列表,在其中您将呈现React组件并对该列表执行this.setState

3)在下一个render调用中,循环访问this.state中的节点列表并创建门户。

代码看起来像这样:

import {DockPanel, Widget} from "@phosphor/widgets";
import {createPortal} from "react-dom";

interface IWidgetInfo {
  component: JSX.Element;
  node: HTMLElement;
}

interface IDockState {
  widgetInfos: IWidgetInfo[];
}

interface IDockProps {
  children: JSX.Element[];
}

class WrapperWidget extends Widget {
  constructor(name: string, node: HTMLElement) {
    super({node});
    this.setFlag(Widget.Flag.DisallowLayout);
    this.title.label = name;
  }
}

export class Dock extends React.PureComponent<IDockProps, IDockState> {
  elem: HTMLElement;
  dock: DockPanel;

  componentDidMount() {
    this.dock = new DockPanel(this.context.store);

    let widgetInfos = [];
    for (let component of this.props.children) {
      let node = document.createElement("div");
      let widget = new WrapperWidget("Widget Name", node);
      this.dock.addWidget(widget);
      widgetInfos.push({node, component});
    }
    this.setState({...this.state, widgetInfos});

    Widget.attach(this.dock, this.elem);
  }

  render() {
    return (
      <div ref={(c) => this.elem = c}>
          {this.state.widgetsInfos.map(widgetInfo => {
             return createPortal(widgetInfo.component, widgetInfo.node);
          })}
      </div>
    );
  }
}