我试图通过使用状态将子组件更改为另一个组件。这会正确地注入新的组件,但是,如果我想动态更改其道具,则不会发生任何变化。 componentWillReceiveProps
未被触发。
在我的场景中,我会有许多组件,如TestComponent
(近20-30个组件),它们都有不同的HTML布局(它们也有子组件)。我通过从某个列表中选择一些值来在这些组件之间切换。
我认为最初加载所有这些组件并不是一个好主意。另一方面,我还没有发现任何关于在主Component中动态注入Component的事情。
这是我想要实现的一个非常基本的例子。点击按钮后,我在TestComponent
内插入了App
。之后,每隔一秒,我递增一个状态值,我尝试绑定TestComponent
但是,组件值没有更新。
如果我在setInterval
函数中使用注释片段而不是取消注释,它可以工作,但我必须编写20-30开关案例,以便在我的实际代码中找到正确的组件(我在从中选择一个值时也写过列表)所以,我想避免使用它。另外,我不确定性能。
那么,这是正确的方法,如果是这样,我该如何解决这个问题呢?如果错了,我还能尝试什么?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
component: <p>Initial div</p>,
componentData: 0
};
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler = () => {
this.setState({
component: <TestComponent currentValue={this.state.componentData} />
});
setInterval(() => {
this.setState({
componentData: this.state.componentData + 1
})
// This will update TestComponent if used instead of above
/*this.setState({
componentData: this.state.componentData + 1,
component: <TestComponent currentValue={this.state.componentData} />
});*/
}, 1000)
}
render() {
return(
<div>
<h4>Click the button</h4>
<button onClick={this.onClickHandler}>Change Component</button>
{this.state.component}
</div>
)
}
}
class TestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
currentValue: this.props.currentValue
};
}
componentWillReceiveProps(nextProps) {
this.setState({
currentValue: nextProps.currentValue
});
}
render() {
return (
<p>Current value: {this.state.currentValue}</p>
)
}
}
ReactDOM.render(
<App />
,document.getElementById("app"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app" style="width: 200px; height: 200px;"></div>
&#13;
答案 0 :(得分:1)
要动态渲染子组件,可以在父级中使用React.createElement方法,这样可以调用不同的组件,这可以用作下面的示例代码,希望它有所帮助。
getChildComponent = (childComponentName) => {
const childComponents = {
TestComponent1,
TestComponent2,
TestComponent3,
TestComponent4
},
componentProps = Object.assign({}, this.props,this.state, {
styles: undefined
});
if (childComponents[childComponentName]) {
return React.createElement(
childComponents[childComponentName],
componentProps);
}
return null;
}
render(){
this.getChildComponents(this.state.childComponentName);
}
这里在render函数中传递组件名称,child将呈现dynalicaaly。其他方法可以是,将childComponents对象作为数组,查看下面的样本
const childComponents = [
TestComponent1,
TestComponent2,
TestComponent3,
TestComponent4
]
注意:您必须在父级中导入所有子组件,这些组件 不是字符串。
答案 1 :(得分:1)
那是因为Facebook在他们的React文档中提到过。
当您致电
setState()
时,React会将您提供的对象合并到当前状态。合并很浅
了解更多信息read the documentation
因此,对于这种情况,唯一修改后的值为componentData
而component
不会触发任何更新
解决此问题的一个更好的案例是使用 Higher-Order components (HOC) ,因此App
组件并不关心您尝试渲染的组件而是只接收一个组件作为道具,因此您可以在App
状态下将道具传递给此组件。
此外,您不需要TestComponent
中的州,因为您获得了作为道具的价值,并由App
处理。
我还添加了一个条件来阻止添加多个setInterval
class App extends React.Component {
interval;
constructor(props) {
super(props);
this.state = {
componentData: 0
};
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler = () => {
if (!this.interval) {
this.setState({
componentData: this.state.componentData + 1
});
this.interval = setInterval(() => {
this.setState({
componentData: this.state.componentData + 1
});
}, 1000);
}
}
render() {
let Timer = this.props.timer;
return(
<div>
<h4>Click the button</h4>
<button onClick={this.onClickHandler}>Change Component</button>
{!this.state.componentData ? <p>Initial div</p> : <Timer currentValue={this.state.componentData} />}
</div>
)
}
}
class TestComponent extends React.Component {
render() {
const { currentValue } = this.props;
return (
<p>Current value: {currentValue}</p>
)
}
}
ReactDOM.render(<App timer={TestComponent} /> ,document.getElementById("app"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.js"></script>
<div id="app" style="width: 200px; height: 200px;"></div>
&#13;