2015-05-11 5 views
13

У меня есть строка, которая содержит имя класса (это происходит из json-файла). Эта строка сообщает моему классу шаблонов, какой макет/шаблон использовать для данных (также в json). Проблема в том, что мой макет не отображается.Создайте экземпляр класса React из строки

Home.jsx:

//a template or layout. 
var Home = React.createClass({ 
    render() { 
    return (
    <div>Home layout</div> 
    ) 
    } 
}); 

Template.jsx:

var Template = React.createClass({ 
    render: function() { 
    var Tag = this.props.template; //this is the name of the class eg. 'Home' 
    return (
     <Tag /> 
    ); 
    } 
}); 

Я не получаю никаких ошибок, но я также не вижу макет/Home Class. Я проверил файл props.template, и это ведет к правильной информации. Кроме того, я могу видеть домашний элемент в DOM. Однако это выглядит следующим образом:

<div id='template-holder> 
    <home></home> 
</div> 

Если я изменяю следующую строчку:

var Tag = Home; 
//this works but it's not dynamic! 

Любые идеи, как я могу это исправить? Я уверен, что это либо простое исправление, либо я делаю что-то глупое. Помощь была бы оценена. Извините, если это уже было задано (я не мог найти его).

Спасибо, Ewan

ответ

9

Это не будет работать:

var Home = React.createClass({ ... }); 

var Component = "Home"; 
React.render(<Component />, ...); 

Однако это будет:

var Home = React.createClass({ ... }); 

var Component = Home; 
React.render(<Component />, ...); 

Так что вам просто нужно найти способ отображения между строки"Home" и класс компонентаHome. Простой объект будет работать как основной реестр, и вы можете построить оттуда, если вам нужно больше функций.

var components = { 
    "Home": Home, 
    "Other": OtherComponent 
}; 

var Component = components[this.props.template]; 
+2

Спасибо, я надеялся избежать наличия карт/ссылок в коде. Я хотел бы иметь возможность добавлять шаблоны без изменения основной базы кода. Разве это невозможно? – ewan

+0

@ewan. Вы можете создать какой-то глобальный реестр и зарегистрировать каждый компонент, когда он будет создан с помощью 'React.createClass' (например, путем его переноса в вызов функции или что-то еще), но вам определенно нужно будет получить ссылки на фактические компоненты , –

1

При использовании JSX вы можете либо визуализировать HTML-теги (строки), либо компоненты React (классы).

Когда вы уаг Tag = Home, он работает, потому что компилятор JSX преобразует его:

var Template = React.createElement(Tag, {}); 

с переменной Tag в том же объеме и быть Реагировать класса.

var Tag = Home = React.createClass({ 
         render() { 
         return (
         <div>Home layout</div> 
         ) 
         } 
        }); 

Когда вы

var Tag = this.props.template; // example: Tag = "aClassName" 

вы делаете

var Template = React.createElement("aClassName", null); 

Но "aClassName" не является допустимым HTML тегов.

Look here

5

Если вы можете жить с наличием всех компонент в одном модуле, то работает без необходимости вручную сопоставить классы словаря:

import * as widgets from 'widgets'; 
    var Type = widgets[this.props.template]; 
    ... 
    <Type /> 

Оператор импорта подстановочного уже словарь и код работают как реестр в предыдущем ответе.

На самом деле, я думаю, вы могли бы работать с несколькими модулями с одним дополнительным отображением:

import * as widgets from 'widgets'; 
import * as widgets2 from 'widgets2'; 

const registry = Object.assign({}, widgets, widgets2); 
const widget = registry[this.props.template]; 

Я бы полностью сделать это. На самом деле, я думаю.

1

У меня была такая же проблема, и я нашел решение самостоятельно. Я не знаю, является ли «наилучшей оценкой», но она работает, и я использую ее в настоящее время в своем решении.

Вы можете просто использовать «злую» функцию eval для динамического создания экземпляра реагирующего компонента. Что-то вроде:

function createComponent(componentName, props, children){ 
    var component = React.createElement(eval(componentName), props, children); 
    return component; 
} 

Тогда, просто позвоните туда, где вы хотите:

var homeComponent = createComponent('Home', [props], [...children]); 

Если это соответствует вашим потребностям, может быть, вы можете рассмотреть что-то вроде этого.

Надеюсь, это поможет.

+0

Я бы не считал «eval» злым, если пользователь не может ввести все, что захочет. – xanderiel

Смежные вопросы