简体   繁体   English

使用React Portal将子项呈现为父组件的DOM节点

[英]Use React Portal to render a child into a DOM node of the parent component

What I am attempting to do might seem a little unorthodox so please bear with me. 我试图做的事情可能看起来有点不正统,所以请耐心等待。

I want to render a child component into a DOM node of the parent component using a React Portal. 我想使用React Portal将子组件渲染到父组件的DOM节点中。

You might think: "This is not the purpose of a Portal and you should just render you children where you want them." 你可能会想:“这不是门户网站的目的,你应该只是让孩子们在你想要的地方。”

And you may be right but this is a simplified example of an experimental approach I am attempting after trying many other ways. 你可能是对的,但这是我在尝试许多其他方法后尝试的实验方法的简化示例。

Anyways, here is the code: (sandbox here) 无论如何,这里是代码:( 沙盒在这里)

const Child = ({ color }) => {
  let jsx = <h1>Wow! I am {color}!</h1>;
  let node = document.getElementById(color);
  return ReactDOM.createPortal(jsx, node);
};

class Parent extends React.Component {
  state = {
    color: "green"
  };
  changeColor = () => {
    let color = this.state.color === "green" ? "blue" : "green";
    this.setState({ color });
  };
  render() {
    return (
      <div className="App">
        <Child color={this.state.color} />
        <button onClick={this.changeColor}>change color</button>
        <div className="green" id="green">
          I render green stuff:
        </div>
        <div className="blue" id="blue">
          I render blue stuff:
        </div>
      </div>
    );
  };
};

The problem is that the Parent component's "blue" and "green" divs are not yet rendered when the Child tries to render some jsx into them. 问题是,当Child尝试将一些jsx渲染到它们时,尚未呈现父组件的“蓝色”和“绿色”div。 So I get the error Target container is not a DOM element . 所以我得到错误Target container is not a DOM element The only way I got it to work is have placing those divs into the html file at the root level. 我让它工作的唯一方法是将这些div放入根级别的html文件中。

Any advice for how to do what I am trying with Portals? 有关如何使用门户网站进行操作的任何建议吗? Please don't say to just do this: 请不要说只是这样做:

<div className="App">
  <button onClick={this.changeColor}>change color</button>
  <div className="green" id="green">
    I render green stuff:
    {this.state.color === 'green' && <Child color='green' />}
  </div>
  <div className="blue" id="blue">
    I render blue stuff:
    {this.state.color === 'blue' && <Child color='blue' />}
  </div>
</div>

Thank you in advance :-) 先感谢您 :-)

Yeah, so your issue is that you can't (at that point) look up the divs by their id as they are rendered by the parent component and they just aren't in the DOM as you'd think. 是的,所以你的问题是你不能(在那一点上)通过他们的id查找div,因为它们是由父组件呈现的,并且它们不像你想象的那样在DOM中。

However! 然而! You can just use refs to save the day! 你可以使用refs来节省一天! Here is an example: https://codesandbox.io/s/r78mplox64?fontsize=14 以下是一个示例: https//codesandbox.io/s/r78mplox64?fontize = 14

I replaced the class for functional components because the hooks might make it clearer. 我替换了类的功能组件,因为钩子可能会使它更清晰。 Basically, it all it does it pass two refs to the color divs and after render, the current value of the refs would point the node. 基本上,它只是将两个引用传递给颜色div,并且在渲染之后,refs的当前值将指向节点。 The useEffect on mount sets the state of colorNode to the current value of the blue ref (which is the <div id="blue"> node). useEffect上安装设置的状态colorNode蓝色ref的电流值(其是<div id="blue">节点)。

Then, the button click just swaps out the color variable and color node. 然后,按钮单击只是交换颜色变量和颜色节点。 Both are then passed in as props and the colorNode prop is passed as the node for the portal to render to. 然后将两者作为props传递,并将colorNode prop作为要呈现的门户的节点传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM