Имя динамического компонента 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>);
}
...