[javascript] 반응 / JSX 동적 구성 요소 이름

유형에 따라 구성 요소를 동적으로 렌더링하려고합니다.

예를 들면 다음과 같습니다.

var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent />  instead of <ExampleComponent />

여기에 제안 된 솔루션을 시도했습니다 .React / JSX 동적 구성 요소 이름

컴파일 할 때 오류가 발생했습니다 (gulp에 browserify 사용). 배열 구문을 사용하고있는 XML을 기대했습니다.

모든 구성 요소에 대한 방법을 만들어서 해결할 수 있습니다.

newExampleComponent() {
    return <ExampleComponent />;
}

newComponent(type) {
    return this["new" + type + "Component"]();
}

그러나 그것은 내가 만드는 모든 구성 요소에 대한 새로운 방법을 의미합니다. 이 문제에 대한보다 우아한 해결책이 있어야합니다.

나는 제안에 매우 개방적이다.



답변

<MyComponent />로 컴파일 React.createElement(MyComponent, {})하면 문자열 (HTML 태그) 또는 함수 (ReactClass)가 첫 번째 매개 변수로 필요합니다.

대문자로 시작하는 이름을 가진 변수에 컴포넌트 클래스를 저장할 수 있습니다. HTML 태그와 반응 구성 요소를 참조하십시오 .

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} />;
}


답변

컴포넌트 이름을 동적으로 사용해야하는 모든 컴포넌트에 맵핑하는 컨테이너가 있어야합니다. 구성 요소 클래스는 컨테이너 환경에 등록해야합니다. 모듈 식 환경에서는 액세스 할 수있는 단일 위치가 없기 때문입니다. name프로덕션에서 기능 이 축소되었으므로 구성 요소 클래스를 명시 적으로 지정하지 않으면 이름으로 식별 할 수 없습니다 .

구성 요소 맵

일반 객체가 될 수 있습니다.

class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;

또는 Map인스턴스 :

const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);

일반 객체는 속성 속기의 이점이 있으므로 더 적합합니다.

배럴 모듈

배럴 모듈 라는 이름의 수출과는지도의 역할을 할 수 있습니다 :

// Foo.js
export class Foo extends React.Component { ... }

// dynamic-components.js
export * from './Foo';
export * from './Bar';

// some module that uses dynamic component
import * as componentsMap from './dynamic-components';

const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;

이것은 모듈 코드 스타일 당 하나의 클래스와 잘 작동합니다.

데코레이터

데코레이터는 구문 설탕의 클래스 구성 요소와 함께 사용할 수 있지만 클래스 이름을 명시 적으로 지정하고 맵에 등록해야합니다.

const componentsMap = {};

function dynamic(Component) {
  if (!Component.displayName)
    throw new Error('no name');

  componentsMap[Component.displayName] = Component;

  return Component;
}

...

@dynamic
class Foo extends React.Component {
  static displayName = 'Foo'
  ...
}

데코레이터는 기능적 구성 요소를 사용하여 고차 구성 요소로 사용할 수 있습니다.

const Bar = props => ...;
Bar.displayName = 'Bar';

export default dynamic(Bar);

의 사용은 비표준displayName 대신 임의의 속성은 또한 디버깅 혜택을 제공합니다.


답변

새로운 해결책을 찾았습니다. 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.createElementES6을 사용하여 직접 사용하는 것 입니다.

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 })
    )
  }
}


답변

구성 요소 맵이있는 모든 옵션에서 ES6 짧은 구문을 사용하여 맵을 정의하는 가장 간단한 방법을 찾지 못했습니다.

import React from 'react'
import { PhotoStory, VideoStory } from './stories'

const components = {
    PhotoStory,
    VideoStory,
}

function Story(props) {
    //given that props.story contains 'PhotoStory' or 'VideoStory'
    const SpecificStory = components[props.story]
    return <SpecificStory/>
}