Reputation: 921
I have a menu component that should be dynamically loading element in another container component. However, the child elements are never rendered.
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;
When the user clicks on a menu option, it triggers OnMenuChange back at the app.js level, which updates the Container component. Which then puts a "MyApp" element in the container div...
But the constructor and render method are never called in the MyApp component.
Update I moved the list of menu items into the App.js file:
let navGroups = [
{
links: [
{
key: "myApp",
name: "My App",
type: MyApp,
}
]
}
];
Then pass that list into the menu which now passes the 'type' back rather than the name. This works better as the name can now have spaces in it.
Upvotes: 0
Views: 1937
Reputation: 106027
Let's consider what this bit of JSX transpiles to:
<this.props.App />
⬇
React.createElement(this.props.App, null)
...and now review what React.createElement
does. From 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).
From the looks of it, this.props.App
in your code is a string. Whether that string is 'div'
or 'MyFancyApp'
, React assumes it's the name of an HTML tag (because how could it do anything else?).
If you want React to treat this.props.App
as a component, the value of this.props.App
has to be an actual component class or function—not a string with the name of a component. You could change the Menu component to pass components instead of strings to OnMenuChange
, or you could make a change like this to the App component:
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]}/>
// ...
);
}
}
Upvotes: 1
Reputation: 1949
I think the issue might be that your state
object is undefined when the first render happens and then prevents any sort of update to it. I would probably just set it to an empty object to initialize it.
class MyComponent extends Component {
state = {
App: null
}
}
Example: https://jsfiddle.net/614ykpgg/9/
Upvotes: 1