使用 React Portal 将子组件渲染到父组件的 DOM 节点中

Ego*_*rov 5 javascript dom reactjs

我正在尝试做的事情可能看起来有点不正统,所以请耐心等待。

我想使用 React Portal 将子组件渲染到父组件的 DOM 节点中。

您可能会想:“这不是 Portal 的目的,您应该让孩子随心所欲。”

你可能是对的,但这是我尝试了许多其他方法后尝试的实验方法的简化示例。

无论如何,这是代码:(这里是沙箱)

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>
    );
  };
};
Run Code Online (Sandbox Code Playgroud)

问题是当子组件尝试将一些 jsx 渲染到它们时,父组件的“蓝色”和“绿色”div 尚未渲染。所以我得到了错误Target container is not a DOM element。我让它工作的唯一方法是将这些 div 放入根级别的 html 文件中。

关于如何使用 Portals 进行尝试的任何建议?请不要说只是这样做:

<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>
Run Code Online (Sandbox Code Playgroud)

先感谢您 :-)

Tom*_*ney 8

是的,所以你的问题是你不能(此时)通过它们的 id 查找 div,因为它们是由父组件渲染的,并且它们并不像你想象的那样位于 DOM 中。

然而!您可以使用 ref 来挽救局面!这是一个示例:https ://codesandbox.io/s/r78mplox64?fontsize=14

我替换了功能组件的类,因为挂钩可能会让它更清晰。基本上,它所做的就是将两个引用传递给颜色 div,并在渲染后,引用的当前值将指向节点。on useEffectmount 将 的状态设置colorNode为蓝色引用(即节点<div id="blue">)的当前值。

然后,单击按钮只会交换颜色变量和颜色节点。然后两者都作为 props 传入,并且colorNodeprop 作为门户渲染的节点传递。