development

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

big-blog 2020. 6. 29. 07:31
반응형

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

새로운 해결책을 찾았습니다. 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 })
    )
  }
}

There should be a container that maps component names to all components that are supposed to be used dynamically. Component classes should be registered in a container because in modular environment there's otherwise no single place where they could be accessed. Component classes cannot be identified by their names without specifying them explicitly because function name is minified in production.

Component map

It can be plain object:

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

Or Map instance:

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

Plain object is more suitable because it benefits from property shorthand.

Barrel module

A barrel module with named exports can act as such map:

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

This works well with one class per module code style.

Decorator

Decorators can be used with class components for syntactic sugar, this still requires to specify class names explicitly and register them in a map:

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'
  ...
}

A decorator can be used as higher-order component with functional components:

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

export default dynamic(Bar);

The use of non-standard displayName instead of random property also benefits debugging.


I used a bit different Approach, as we always know our actual components so i thought to apply switch case. Also total no of component were around 7-8 in my case.

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 we wish to access various views with dynamic component loading.The following code gives a working example of how to accomplish this by using a string parsed from the search string of a url.

Lets assume we want to access a page 'snozberrys' with two unique views using these url paths:

'http://localhost:3000/snozberrys?aComponent'

and

'http://localhost:3000/snozberrys?bComponent'

we define our view's controller like this:

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: Other answers are better, see comments.

I solved the same problem this way:

...
render : function () {
  var componentToRender = 'component1Name';
  var componentLookup = {
    component1Name : (<Component1 />),
    component2Name : (<Component2 />),
    ...
  };
  return (<div>
    {componentLookup[componentToRender]}
  </div>);
}
...

참고URL : https://stackoverflow.com/questions/29875869/react-jsx-dynamic-component-name

반응형