简体   繁体   English

如何动态地将React组件插入DOM(例如对话框)?

[英]How do you dynamically insert a React component into the DOM (for instance a dialog)?

I'd like to replace javascript's built in alert() function with a React Component that handles the same task: namely, showing a quick, dismissible message to the user. 我想用一个处理相同任务的React Component替换javascript内置的alert()函数:即向用户显示一条快速的,可忽略的消息。

Now, I can make this happen by creating a component and placing it in my markup. 现在,我可以通过创建一个组件并将其放置在我的标记中来实现这一目标。 eg 例如

<div> 
    <BunchOfComponents />
    <MoreComponents />

    <MyAlertDialog open={this.props.shouldShowAlert} />
</div>

And then make it show by controlling its open state via Redex or whatever. 然后通过Redex或其他方式控制其open状态以使其显示。

However, what I'd like to do, it be able to not declare it in my markup and instead inject it into the dom via a function. 然而,我想要做什么,它能够在我的标记没有宣布它,而不是将其注入到通过功能的DOM。

Something like... 就像是...

myCoolFunction() {
    const alert = (
        <MyAlert
            open={true}
            msg="Hello World" 
        />
    )
    DOM.findNode('someID').insert(alert);  <-- fake API obviously   
}

Is it possible to dynamically append components like that? 是否可以动态附加这样的组件?

It's possible to inject some custom stuff with DOM manipulation inside of React rendered tree, if it's rendered as an empty node. 如果将其渲染为空节点,则可以在DOM渲染树中注入一些使用DOM操作的自定义内容。 Assuming you have somewhere in react's render: 假设您在react的渲染中有某个地方:

<div id="you-know-id />

You can then find this node by id, and assign its innerHTML with something. 然后,您可以按ID查找此节点,并为其分配innerHTML More 'reactish' way of doing it is using the refs instead of id. 更“反应灵敏”的方法是使用ref而不是id。

Usually, this stuff is being wrapped inside componentDidMount (where you insert) and componentWillUnmount (where you remove and unsubscribe from anything) methods. 通常,这些东西被包装在componentDidMount (您在其中插入)和componentWillUnmount (您在其中删除和取消订阅)方法中。

Because, doing dirty tricks you probably want to avoid memory leaks. 因为,做一些卑鄙的把戏,您可能希望避免内存泄漏。 So, it's the way. 因此,这就是方法。

By the way, I don't think that it's the right way of approaching the problem you just described. 顺便说一句,我认为这不是解决您刚刚描述的问题的正确方法。 What you could do instead, is something like this: 您可以做的是这样的:

{ this.props.shouldShowAlert && <MyAlertDialog open={ true } /> }

And then in will be actually mounted when it's opened, and unmounted when it's closed. 然后,在打开时将实际安装 in,在关闭时将其实际卸载。

Still, it's way safer to control injection with the state or prop member. 不过,使用状态或prop成员控制注入更为安全。 You really need to know what you're doing when you do direct DOM manipulation. 当您执行直接DOM操作时,您确实需要知道您在做什么。 Say, wrapping some jQuery plugin :). 说,包装一些jQuery插件:)。 Then you're fine, cause there are no other way :). 那您就好了,因为没有其他方法:)。

This is the dirty way I do it at work (that didn't sound right...) http://codepen.io/matthsiung/pen/JKOpVW 这是我在工作中做的肮脏的方式(听起来不正确...) http://codepen.io/matthsiung/pen/JKOpVW

I'm sure there's a better 'proper' way to do it but it cleans up after itself so it works for me. 我敢肯定,有一种更好的“适当”方法可以做到这一点,但它会自行清理,因此对我有用。

Here are the key points: 以下是关键点:

Dialog trigger 对话触发

//Your trigger function will render the dialog component to a newly created dummy div,
// while also passing it into the component as a prop

function showDialog() {
  var div = document.createElement('div');
  ReactDOM.render(
     <Dialog container={div}/>,
     document.body.appendChild(div)
  );
} 

Dialog component: 对话框组件:

//When your dialog component closes it unmounts itself
close(){
  ReactDOM.unmountComponentAtNode(this.props.container);
},

//Before unmount it cleans up after itself by removing the dummy div   
componentWillUnmount() {
 document.body.removeChild(this.props.container); 
},

Maybe react-portal can help you. 也许反应门户可以为您提供帮助。

From the docs: 从文档:

transports its child into a new React component and appends it to the document.body (creates a new independent React tree) 将其子级传输到新的React组件中并将其附加到document.body(创建新的独立React树)

I use a lot (for dialogs/modals and menu popups). 我使用很多(用于对话框/模式和菜单弹出窗口)。 Very useful and lightweight. 非常有用且轻巧。

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

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