在 React 中动态添加子组件

我的目标是在页面/父组件上动态添加组件。

我从这样一些基本的示例模板开始:

Js:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);
ReactDOM.render(<SampleComponent name="SomeName"/>, document.getElementById('myId'));

App.js:

var App = React.createClass({
render: function() {
return (
<div>
<h1>App main component! </h1>
<div id="myId">myId div</div>
</div>


);
}


});

样本组件 js:

var SampleComponent = React.createClass({
render: function() {
return (
<div>
<h1>Sample Component! </h1>
</div>
);
}
});

这里将 SampleComponent挂载到 <div id="myId"></div>节点,该节点预先用 App.js模板编写。但是,如果我需要向 App 组件添加不确定数量的组件,该怎么办呢?显然,我不能让所有的 Div所需要的坐在那里。

在阅读了一些教程之后,我仍然不理解组件是如何动态地创建和添加到父组件中的。做这件事的方法是什么?

245654 次浏览

You need to pass your components as children, like this:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(
<App>
<SampleComponent name="SomeName"/>
<App>,
document.body
);

And then append them in the component's body:

var App = React.createClass({
render: function() {
return (
<div>
<h1>App main component! </h1>
{
this.props.children
}
</div>
);
}
});

You don't need to manually manipulate HTML code, React will do that for you. If you want to add some child components, you just need to change props or state it depends. For example:

var App = React.createClass({


getInitialState: function(){
return [
{id:1,name:"Some Name"}
]
},


addChild: function() {
// State change will cause component re-render
this.setState(this.state.concat([
{id:2,name:"Another Name"}
]))
}


render: function() {
return (
<div>
<h1>App main component! </h1>
<button onClick={this.addChild}>Add component</button>
{
this.state.map((item) => (
<SampleComponent key={item.id} name={item.name}/>
))
}
</div>
);
}


});

First, I wouldn't use document.body. Instead add an empty container:

index.html:

<html>
<head></head>
<body>
<div id="app"></div>
</body>
</html>

Then opt to only render your <App /> element:

main.js:

var App = require('./App.js');
ReactDOM.render(<App />, document.getElementById('app'));

Within App.js you can import your other components and ignore your DOM render code completely:

App.js:

var SampleComponent = require('./SampleComponent.js');


var App = React.createClass({
render: function() {
return (
<div>
<h1>App main component!</h1>
<SampleComponent name="SomeName" />
</div>
);
}
});

SampleComponent.js:

var SampleComponent = React.createClass({
render: function() {
return (
<div>
<h1>Sample Component!</h1>
</div>
);
}
});

Then you can programmatically interact with any number of components by importing them into the necessary component files using require.

Firstly a warning: you should never tinker with DOM that is managed by React, which you are doing by calling ReactDOM.render(<SampleComponent ... />);

With React, you should use SampleComponent directly in the main App.

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);

The content of your Component is irrelevant, but it should be used like this:

var App = React.createClass({
render: function() {
return (
<div>
<h1>App main component! </h1>
<SampleComponent name="SomeName"/>
</div>
);
}
});

You can then extend your app component to use a list.

var App = React.createClass({
render: function() {
var componentList = [
<SampleComponent name="SomeName1"/>,
<SampleComponent name="SomeName2"/>
]; // Change this to get the list from props or state
return (
<div>
<h1>App main component! </h1>
{componentList}
</div>
);
}
});

I would really recommend that you look at the React documentation then follow the "Get Started" instructions. The time you spend on that will pay off later.

https://facebook.github.io/react/index.html

Sharing my solution here, based on Chris' answer. Hope it can help others.

I needed to dynamically append child elements into my JSX, but in a simpler way than conditional checks in my return statement. I want to show a loader in the case that the child elements aren't ready yet. Here it is:

export class Settings extends React.PureComponent {
render() {
const loading = (<div>I'm Loading</div>);
let content = [];
let pushMessages = null;
let emailMessages = null;


if (this.props.pushPreferences) {
pushMessages = (<div>Push Content Here</div>);
}
if (this.props.emailPreferences) {
emailMessages = (<div>Email Content Here</div>);
}


// Push the components in the order I want
if (emailMessages) content.push(emailMessages);
if (pushMessages) content.push(pushMessages);


return (
<div>
{content.length ? content : loading}
</div>
)
}

Now, I do realize I could also just put {pushMessages} and {emailMessages} directly in my return() below, but assuming I had even more conditional content, my return() would just look cluttered.