在 React 中渲染动态子组件
Rendering a dynamic child component in React
我有一个菜单组件,它应该在另一个容器组件中动态加载元素。但是,永远不会呈现子元素。
App.js
import React, { Component } from 'react';
import './App.css';
import Menu from './components/navigation/Menu';
import Header from './components/navigation/Header';
import Container from './components/navigation/Container';
class App extends Component {
render() {
return (
<div className="App" >
<Header />
<Menu OnMenuChange={(appName) => { this.setState({ currentApp: appName }) }} />
<Container App={this.state.currentApp}/>
</div>
);
}
}
export default App;
Container.js
import React from 'react';
import './container.css';
import { MyApp } from '../../apps';
class Container extends React.Component {
render() {
return (
<div className="container">
{ this.props.App ? <this.props.App /> : null }
</div>
);
}
}
export default Container;
当用户单击菜单选项时,它会在 app.js 级别触发 OnMenuChange,从而更新 Container 组件。然后将 "MyApp" 元素放入容器 div...
但是在 MyApp 组件中从未调用构造函数和渲染方法。
更新
我将菜单项列表移动到 App.js 文件中:
let navGroups = [
{
links: [
{
key: "myApp",
name: "My App",
type: MyApp,
}
]
}
];
然后将该列表传递到菜单中,菜单现在传递 'type' 而不是名称。这样效果更好,因为名称现在可以包含空格。
我认为问题可能是您的 state
对象在第一次渲染发生时未定义,然后阻止对其进行任何更新。我可能只是将它设置为一个空对象来初始化它。
class MyComponent extends Component {
state = {
App: null
}
}
让我们考虑一下这段 JSX 转换成什么:
<this.props.App />
⬇
React.createElement(this.props.App, null)
...现在回顾一下 React.createElement
的作用。来自 the docs:
createElement()
React.createElement(
type,
[props],
[...children]
)
Create and return a new React element of the given type. The type
argument can be either a tag name string (such as 'div'
or
'span'
), or a React component type (a class or a function).
看来,你代码中的this.props.App
是一个字符串。无论该字符串是 'div'
还是 'MyFancyApp'
,React 都假定它是 HTML 标签的名称(因为它怎么能做其他事情呢?)。
如果你希望 React 将 this.props.App
视为一个组件,this.props.App
的值必须是一个实际的组件 class 或函数——而不是名称为 a 的字符串零件。您可以更改 Menu 组件以将组件而不是字符串传递给 OnMenuChange
,或者您可以像这样对 App 组件进行更改:
import PeopleApp from './PeopleApp';
import PlacesApp from './PlacesApp';
const APPS_BY_NAME = { PeopleApp, PlacesApp };
class App extends Component {
render() {
return (
// ...
<Container App={APPS_BY_NAME[this.state.currentApp]}/>
// ...
);
}
}
我有一个菜单组件,它应该在另一个容器组件中动态加载元素。但是,永远不会呈现子元素。
App.js
import React, { Component } from 'react';
import './App.css';
import Menu from './components/navigation/Menu';
import Header from './components/navigation/Header';
import Container from './components/navigation/Container';
class App extends Component {
render() {
return (
<div className="App" >
<Header />
<Menu OnMenuChange={(appName) => { this.setState({ currentApp: appName }) }} />
<Container App={this.state.currentApp}/>
</div>
);
}
}
export default App;
Container.js
import React from 'react';
import './container.css';
import { MyApp } from '../../apps';
class Container extends React.Component {
render() {
return (
<div className="container">
{ this.props.App ? <this.props.App /> : null }
</div>
);
}
}
export default Container;
当用户单击菜单选项时,它会在 app.js 级别触发 OnMenuChange,从而更新 Container 组件。然后将 "MyApp" 元素放入容器 div...
但是在 MyApp 组件中从未调用构造函数和渲染方法。
更新 我将菜单项列表移动到 App.js 文件中:
let navGroups = [
{
links: [
{
key: "myApp",
name: "My App",
type: MyApp,
}
]
}
];
然后将该列表传递到菜单中,菜单现在传递 'type' 而不是名称。这样效果更好,因为名称现在可以包含空格。
我认为问题可能是您的 state
对象在第一次渲染发生时未定义,然后阻止对其进行任何更新。我可能只是将它设置为一个空对象来初始化它。
class MyComponent extends Component {
state = {
App: null
}
}
让我们考虑一下这段 JSX 转换成什么:
<this.props.App />
⬇
React.createElement(this.props.App, null)
...现在回顾一下 React.createElement
的作用。来自 the docs:
createElement()
React.createElement( type, [props], [...children] )
Create and return a new React element of the given type. The type argument can be either a tag name string (such as
'div'
or'span'
), or a React component type (a class or a function).
看来,你代码中的this.props.App
是一个字符串。无论该字符串是 'div'
还是 'MyFancyApp'
,React 都假定它是 HTML 标签的名称(因为它怎么能做其他事情呢?)。
如果你希望 React 将 this.props.App
视为一个组件,this.props.App
的值必须是一个实际的组件 class 或函数——而不是名称为 a 的字符串零件。您可以更改 Menu 组件以将组件而不是字符串传递给 OnMenuChange
,或者您可以像这样对 App 组件进行更改:
import PeopleApp from './PeopleApp';
import PlacesApp from './PlacesApp';
const APPS_BY_NAME = { PeopleApp, PlacesApp };
class App extends Component {
render() {
return (
// ...
<Container App={APPS_BY_NAME[this.state.currentApp]}/>
// ...
);
}
}