Рендеринг компонента React на основе его имени

Контекст: я разрабатываю веб-приложение на основе виджетов (например, несуществующий iGoogle, где пользователи могут выбирать, какие виджеты они хотят отображать). Каждый виджет является компонентом React.

Упрощенный пример: вот 2 разных виджета

var HelloWidget = React.createClass({
    render: function() { return <div>Hello {this.props.name}</div>; }
});

var HiWidget = React.createClass({
    render: function() {  return <div>Hi {this.props.name}</div>; }
});

Как пользователь, я выбрал HiWidget, и меня зовут «чувак», поэтому, когда система получает мои предпочтения из уровня сохраняемости, это выглядит так:

var dataFromDb = {
    type: 'HiWidget',
    name: 'dude'
};

Как я могу отобразить компонент React, если у меня есть его имя в строке var?

Я попробовал это на основе динамического рендеринга компонента React:

React.render(
  <dataFromDb.type name={dataFromDb.name} />,
  document.getElementById('try2')
);

Раньше он работал с React 0.11, но больше не работает.

И я хотел бы избежать гигантского оператора switch:

switch (dataFromDb.type) {
    case 'HiWidget':
        var component = <HiWidget name={dataFromDb.name} />;
        break;
    case 'HelloWidget':
        var component = <HelloWidget name={dataFromDb.name} />;
        break;
}
React.render(
  component,
  document.getElementById('try3')
);

JSFiddle со всем этим кодом здесь: http://jsfiddle.net/61xdfjk5/


person al8anp    schedule 22.03.2015    source источник


Ответы (2)


Вы можете использовать объект для поиска типа компонента и хранить детали его рендеринга в одном месте:

var components = {
  'HiWidget': HiWidget,
  'HelloWidget': HelloWidget
}

var Component = components[dataFromObj.type]
React.render(
  <Component name={dataFromObj.name}/>,
  document.getElementById('try3')
)
person Jonny Buchanan    schedule 22.03.2015

JSX — это надмножество JavaScript, поэтому вы всегда можете использовать собственный синтаксис JavaScript внутри JSX. Например, если классы ваших компонентов доступны в глобальном пространстве (window), вы можете сделать следующее:

React.render(
  React.createElement(window[dataFromDb.type], {name: dataFromDb.name}),
  document.getElementById('try2')
);

JSFiddle здесь.

person Vadim    schedule 22.03.2015
comment
Не понимаю, зачем здесь window[...]! Переменная dataFromDb находится в области видимости, поскольку dataFromDb.name работает нормально, но если я удалю window[...], она больше не будет работать. - person al8anp; 22.03.2015
comment
@al8anp Вам нужно window[...], потому что таким образом вы получаете ссылку на класс, а dataFromDb.name - это просто строковое представление имени класса. React.createElement(...) ожидает класс в качестве первого аргумента - person Vadim; 22.03.2015