是否可以将反应上下文注入根外的div反应(在body下)

Is it possible to inject react context to div outside the root in react (under the body)

我正在使用 React cytoscape 库。尝试集成到 cytoscape 的 popper 插件。 popper "content" 属性 期望 return 一个 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>

作为 , portals 解决此用例:

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.

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

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")
);
<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>


您在评论中说:

the popper creates those 'divs' dynamically. Hence, I cant create 'MyPortal' component initially.

只需要有条件地创建门户即可。这是上面的内容,但带有 show/hide 门户的按钮:

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")
);
<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>