简体   繁体   中英

Rendering a dynamic child component in React

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.

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/

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]}/>
      // ...
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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