在React

时间:2017-09-01 19:46:54

标签: javascript reactjs es6-modules

我有一个菜单组件,应该在另一个容器组件中动态加载元素。但是,子元素永远不会被渲染。

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组件中永远不会调用构造函数和render方法。

更新 我将菜单项列表移动到App.js文件中:

let navGroups = [
  {
    links: [
      {
        key: "myApp",
        name: "My App",
        type: MyApp,
      }
    ]
  }
];

然后将该列表传递到菜单中,该菜单现在将'type'传递回而不是名称。这样做效果更好,因为名称现在可以包含空格。

2 个答案:

答案 0 :(得分:1)

我认为问题可能是您的state对象在第一次渲染发生时未定义,然后阻止对它进行任何类型的更新。我可能只是将它设置为一个空对象来初始化它。

class MyComponent extends Component {
  state = {
    App: null
  }
}

示例: https://jsfiddle.net/614ykpgg/9/

答案 1 :(得分:1)

让我们考虑一下JSX的这一点:

<this.props.App />

React.createElement(this.props.App, null)

...现在查看React.createElement的内容。来自the docs

  

的createElement()

React.createElement(
  type,
  [props],
  [...children]
)
     

创建并返回给定类型的新React元素。类型   参数可以是标签名称字符串(例如'div'或   'span')或React组件类型(类或函数)。

从它的外观来看,代码中的this.props.App是一个字符串。无论该字符串是'div'还是'MyFancyApp',React都认为它是HTML标记的名称(因为它怎么能做其他事情?)。

如果您希望React将this.props.App视为一个组件,this.props.App的值必须是实际的组件类或函数 - 而不是具有组件名称的字符串。您可以更改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]}/>
      // ...
    );
  }
}