我有一个反应应用程序,在其中一个组件中我想渲染一个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>
不确定是否可以完成。
答案 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>
);
}
}