Рендеринг динамического дочернего компонента в 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;

Контейнер.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;

Когда пользователь щелкает пункт меню, он запускает OnMenuChange на уровне app.js, который обновляет компонент Container. Который затем помещает элемент "MyApp" в контейнер div...

Но конструктор и метод рендеринга никогда не вызываются в компоненте MyApp.

Обновить Я переместил список пунктов меню в файл App.js:

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

Затем передайте этот список в меню, которое теперь передает «тип», а не имя. Это работает лучше, так как имя теперь может содержать пробелы.


person Patrick Dench    schedule 01.09.2017    source источник


Ответы (2)


Давайте рассмотрим, во что транспилируется этот фрагмент JSX:

<this.props.App />

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

...а теперь посмотрите, что делает React.createElement. Из документов:

создатьЭлемент()

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

Создайте и верните новый элемент React заданного типа. Аргумент типа может быть либо строкой имени тега (например, 'div' или 'span'), либо типом компонента React (класс или функция).

Судя по всему, this.props.App в вашем коде — это строка. Независимо от того, является ли эта строка 'div' или 'MyFancyApp', React предполагает, что это имя тега HTML (потому что как он может делать что-то еще?).

Если вы хотите, чтобы React рассматривал this.props.App как компонент, значение this.props.App должно быть фактическим классом или функцией компонента, а не строкой с именем компонента. Вы можете изменить компонент меню, чтобы передавать компоненты вместо строк в OnMenuChange, или вы можете внести такие изменения в компонент приложения:

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]}/>
      // ...
    );
  }
}
person Jordan Running    schedule 01.09.2017
comment
Принимая в качестве ответа, поскольку он точно описывает, что мне нужно было сделать, чтобы заставить это работать. - person Patrick Dench; 01.09.2017

Я думаю, проблема может заключаться в том, что ваш объект state не определен, когда происходит первый рендеринг, а затем предотвращает какое-либо обновление для него. Я бы, вероятно, просто установил его в пустой объект, чтобы инициализировать его.

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

Пример: https://jsfiddle.net/614ykpgg/9/

person 3066d0    schedule 01.09.2017
comment
Хорошо, ваш ответ привел меня в правильном направлении !!! Короткая версия: мне не понравился тот факт, что это была переданная строка. Мое решение состояло в том, чтобы переместить импорт MyApp в модуль App.js, а затем передать список приложений в меню. Теперь onMenuChange передает класс, связанный с элементом, вместо его имени. - person Patrick Dench; 01.09.2017