在不同位置渲染组件

时间:2018-10-28 18:31:58

标签: javascript reactjs

这是我的react app组件结构

<App>
    <Body>
        <Top>
            ### //<- Position 1
        </Top>
        <Middle>
            <MyComponent/>
        </Middle>
    </Body>
</App>

我希望<MyComponent/>随时在Position 1处呈现。 我已经尝试过ReactDom.createPortal,但一直得到Target container is not a DOM element。如果这不可能,那么我如何才能最好地完成类似的设置。

我尝试过的

//Top.js
<Top>
    <div id="top-render"/>
</Top>

//MyCustomElement.js
class MyCustomElement extends Component{
    render(){
        return (<div>Demo Text</div>)
    }
}

export default props => ReactDOM.createPortal(
    <MyCustomElement />,
    document.getElementById('top-render'),
);

//Middle.js
<Middle><MyCustomElement/></Middle>

3 个答案:

答案 0 :(得分:4)

您将收到Target container is not a DOM element错误,因为在执行到达您的ReactDOM.createPortal()调用时,document.getElementById('top-render')试图检索的DOM节点尚未写入到DOM。

这是因为到那时,React还没有成功通过组件树。也就是说,React尚未成功创建组件树中所有内容的虚拟表示,因此尚未向DOM写入任何内容。因此,尽管您期望top-render div在DOM中存在,但实际上尚未编写。

解决方案是创建一个<MyComponent拥有的DOM节点,其中将包含它的子节点(我们称此节点el),然后将该DOM节点作为目标{ {1}}调用(又是第二个参数)。然后,在挂载React.createPortal()时,您只需检索<MyComponent> div并将top-render附加到它。像这样:

el

我整理了一个working example

这种方法行之有效,因为React保证const MyCustomComponent = () => { return (<div>Demo Text: from "MyCustomComponent"</div>) } class MyComponent extends React.Component { el = document.createElement("div"); componentDidMount() { // saving this on the component so we can access it in `componentWillUnmount` later this.targetEl = document.getElementById("top-render"); this.targetEl.appendChild(this.el); } componentWillUnmount() { this.targetEl.removeChild(this.el); } render() { return ReactDOM.createPortal(<MyCustomComponent />, this.el); } } 将在组件安装后立即被调用(也称为写入DOM)。换句话说,我们可以肯定地知道,到componentDidMount()被调用时,我们的组件树至少已被写入DOM一次,因此componentDidMount() div已存在于DOM中。

答案 1 :(得分:0)

“随时导入”是什么意思?

无论如何,您只能使用条件渲染。它将完成工作,但看来您的意图还不是其他!

render(){
 const { showMyComp } = this.state
 return(
   <App>
    <Body>
        <Top>
            {showMyComp && (<MyComponent />)}
        </Top>
        <Middle>
            <MyComponent/>
        </Middle>
    </Body>
   </App>
 )
}

答案 2 :(得分:0)

建议在React App范围之外的ReactDom.createPortal节点上使用

DOM。在内部,您通常应<Top><MyComponent/></Top>声明一个组件。

但是出于好奇,如果只想使用这种方法,则应在Top元素中使用DOM节点的引用。

ReactDOM.createPortal(
    <MyComponent/>,
    /*Ref of Container element*/,
);