Имя динамического компонента React / JSX
Я пытаюсь динамически отображать компоненты на основе их типа.
например:
var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent /> instead of <ExampleComponent />
я попробовал решение, предложенное здесь React / JSX динамические имена компонентов
это дало мне ошибку при компиляции (используя browserify для gulp). Он ожидал XML, где я использовал синтаксис массива.
я мог бы решить эту проблему, создав метод для каждого компонента:
newExampleComponent() {
return <ExampleComponent />;
}
newComponent(type) {
return this["new" + type + "Component"]();
}
но это означало бы новый метод для каждый компонент, который я создаю. Должно быть более элегантное решение этой проблемы.
Я очень открыт для предложений.
8 ответов
<MyComponent />
компилируется в React.createElement(MyComponent, {})
, который ожидает строку (HTML-тег) или функцию (ReactClass) в качестве первого параметра.
вы можете просто сохранить класс компонента в переменной с именем, которое начинается с заглавной буквы. См.HTML-теги против компонентов React.
var MyComponent = Components[type + "Component"];
return <MyComponent />;
компилируется в
var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
существует официальная документация о том, как обращаться с такими ситуациями, доступна здесь: https://facebook.github.io/react/docs/jsx-in-depth.html#choosing-the-type-at-runtime
в основном он говорит:
неправильно:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}
правильно:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
Я придумал новое решение. Обратите внимание, что я использую модули ES6, поэтому мне нужен класс. Вместо этого можно определить новый класс React.
var components = {
example: React.createFactory( require('./ExampleComponent') )
};
var type = "example";
newComponent() {
return components[type]({ attribute: "value" });
}
Если ваши компоненты глобальны, вы можете просто сделать:
var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});
для компонента оболочки простым решением было бы просто использовать React.createElement
напрямую (с помощью ES6).
import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'
class Button extends React.Component {
render() {
const { type, ...props } = this.props
let button = null
switch (type) {
case 'flat': button = FlatButton
break
case 'icon': button = IconButton
break
default: button = RaisedButton
break
}
return (
React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
)
}
}
я использовал немного другой подход, так как мы всегда знаем наши фактические компоненты, поэтому я подумал применить случай переключателя. Также нет деталей по 7-8 в моем случае.
getSubComponent(name) {
let customProps = {
"prop1" :"",
"prop2":"",
"prop3":"",
"prop4":""
}
switch (name) {
case "Component1": return <Component1 {...this.props} {...customProps} />
case "Component2": return <Component2 {...this.props} {...customProps} />
case "component3": return <component3 {...this.props} {...customProps} />
}
}
Suspose мы хотим получить доступ к различным представлениям с динамической загрузкой компонентов.В следующем коде приведен рабочий пример выполнения этого с помощью строки, проанализированной из строки поиска url-адреса.
предположим, мы хотим получить доступ к странице "snozberrys" с двумя уникальными представлениями, используя следующие пути url:
'http://localhost:3000/snozberrys?aComponent'
и
'http://localhost:3000/snozberrys?bComponent'
мы определяем контроллер нашего вида следующим образом:
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router,
Route
} from 'react-router-dom'
import AComponent from './AComponent.js';
import CoBComponent sole from './BComponent.js';
const views = {
aComponent: <AComponent />,
console: <BComponent />
}
const View = (props) => {
let name = props.location.search.substr(1);
let view = views[name];
if(view == null) throw "View '" + name + "' is undefined";
return view;
}
class ViewManager extends Component {
render() {
return (
<Router>
<div>
<Route path='/' component={View}/>
</div>
</Router>
);
}
}
export default ViewManager
ReactDOM.render(<ViewManager />, document.getElementById('root'));
Edit: другие ответы лучше, см. комментарии.
Я решил ту же проблему следующим образом:
...
render : function () {
var componentToRender = 'component1Name';
var componentLookup = {
component1Name : (<Component1 />),
component2Name : (<Component2 />),
...
};
return (<div>
{componentLookup[componentToRender]}
</div>);
}
...