是否可以将react上下文注入react根目录之外的div(在body下面)

cry*_*oun 4 javascript cytoscape.js reactjs popper.js react-context

我正在使用 React cytoscape 库。尝试集成到 cytoscape 的 popper 插件。popper“content”属性期望返回一个 div 元素,描述附加到“body”元素的 popper。由于上下文提供者位于根元素下,因此该 div 不能成为该上下文的使用者。如何在根外部定义的 popper 元素中使用相同的上下文。

使用 cytoscape 的 React 组件,但 cytoscape 的插件是纯 js 的。

<body>
 <div id=root>
  <Style_Provider>
      .
      .
      .
  </Style_Provider>
 </div>
 <div id="popper">
    // need to access to style context
 </div>
</body>
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 5

正如Eric Hasselbring 所说门户解决了这个用例:

门户提供了一种一流的方法来将子组件渲染到存在于父组件 DOM 层次结构之外的 DOM 节点中。

这是一个使用上下文的示例:

const ExampleContext = React.createContext(
    "default context"
);

class Example extends React.Component {
    render() {
        return (
            <ExampleContext.Provider value="context from Example">
              <div>
                  This is the parent comnponent.
                  <MyPortal />
              </div>
            </ExampleContext.Provider>
        );
    }
}

class MyPortal extends React.Component {
    static contextType = ExampleContext;
    render() {
        return ReactDOM.createPortal(
            <div>This is "my portal," context stuff is "{this.context}"</div>,
            document.getElementById("portal")
        );
    }
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
Run Code Online (Sandbox Code Playgroud)
<div id="root"></div>
<hr>
<div id="portal"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Run Code Online (Sandbox Code Playgroud)


在评论中你说:

popper 动态创建这些“div”。因此,我最初无法创建“MyPortal”组件。

只需将门户的创建设为有条件即可。这是上面的内容,但有一个显示/隐藏门户的按钮:

const ExampleContext = React.createContext(
    "default context"
);

class Example extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            showPortal: false
        };
        this.showHideClick = this.showHideClick.bind(this);
    }

    showHideClick() {
        this.setState(({showPortal}) => ({showPortal: !showPortal}));
    }

    render() {
        const {showPortal} = this.state;
        return (
            <ExampleContext.Provider value="context from Example">
              <div>
                  This is the parent comnponent.
                  <input type="button" value={showPortal ? "Hide" : "Show"} onClick={this.showHideClick}/>
                  {showPortal && <MyPortal />}
              </div>
            </ExampleContext.Provider>
        );
    }
}

class MyPortal extends React.Component {
    static contextType = ExampleContext;
    render() {
        return ReactDOM.createPortal(
            <div>This is "my portal," context stuff is "{this.context}"</div>,
            document.getElementById("portal")
        );
    }
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
Run Code Online (Sandbox Code Playgroud)
<div id="root"></div>
<hr>
<div id="portal"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Run Code Online (Sandbox Code Playgroud)