प्रतिक्रिया / JSX डायनेमिक घटक नाम


168

मैं उनके प्रकार के आधार पर घटकों को गतिशील रूप से प्रस्तुत करने की कोशिश कर रहा हूं।

उदाहरण के लिए:

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

मैंने यहां प्रस्तावित रेक्ट / जेएसएक्स गतिशील घटक नामों के समाधान की कोशिश की

संकलन करते समय (gulp के लिए ब्राउज़र का उपयोग करते हुए) मुझे एक त्रुटि मिली। यह एक्सएमएल की उम्मीद करता था जहां मैं एक सरणी सिंटैक्स का उपयोग कर रहा था।

मैं हर घटक के लिए एक विधि बनाकर इसे हल कर सकता था:

newExampleComponent() {
    return <ExampleComponent />;
}

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

लेकिन मेरे द्वारा बनाए गए हर घटक के लिए एक नई विधि का मतलब होगा। इस समस्या का अधिक सुरुचिपूर्ण समाधान होना चाहिए।

मैं सुझावों के लिए बहुत खुला हूं।

जवाबों:


158

<MyComponent />संकलन करता है React.createElement(MyComponent, {}), जो पहले पैरामीटर के रूप में एक स्ट्रिंग (HTML टैग) या फ़ंक्शन (ReactClass) की अपेक्षा करता है।

आप अपने घटक वर्ग को एक नाम के साथ एक चर में स्टोर कर सकते हैं जो एक बड़े अक्षर से शुरू होता है। HTML टैग बनाम रिएक्ट घटक देखें ।

var MyComponent = Components[type + "Component"];
return <MyComponent />;

के लिए संकलित करता है

var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});

5
भविष्य के पाठकों को संभवतः {...this.props}माता-पिता से उप-घटकों को पारदर्शी रूप से पास करने के लिए उपयोगी मिलेगा । जैसेreturn <MyComponent {...this.props} />
Dr.Strangelove

4
यह भी सुनिश्चित करें कि आप अपने डायनामिक वैरिएबल नाम को कैपिटलाइज़ करते हैं।
सादा

28
ध्यान रखें कि आपके चर को घटक को ही पकड़ना चाहिए न कि केवल एक स्ट्रिंग के रूप में घटक का नाम ।
तात्यामेली

3
यदि आप यह भी सोच रहे हैं कि var को facebook.github.io/react/docs/… को कैपिटल करने की आवश्यकता क्यों है
नोबिता

3
घटक अपरिभाषित हैं
नेस-ईई

144

ऐसी स्थितियों से निपटने के बारे में एक आधिकारिक दस्तावेज यहां उपलब्ध है: 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} />;
}

25
बहुत महत्वपूर्ण बात: एक पूंजीकृत चर
mpyw

4
इस तथ्य के अलावा कि यह आधिकारिक डॉक्स है, यह आसानी से सबसे अच्छा उत्तर और सबसे संरचित समाधान है। शायद इसीलिए यह डॉक्स में है
:)

1
महान जवाब के लिए धन्यवाद। निम्नलिखित पाठकों के लिए, ध्यान दें कि मैप ऑब्जेक्ट के भीतर का मूल्य (यहां मैप ऑब्जेक्ट ऑब्जेक्ट कास्ट कंपोनेंट्स है और वैल्यू फोटोस्टोरी और वीडियोस्टोरी है) उद्धरण चिह्नों के बिना होना चाहिए - अन्यथा, घटक रेंडर नहीं करेगा और आपको त्रुटि मिलेगी - मेरे मामला मैं इसे याद किया और बस समय बर्बाद किया ...
इरेज़ लिबरमैन

11

एक कंटेनर होना चाहिए जो सभी घटकों को घटक नामों को मैप करता है जिन्हें गतिशील रूप से उपयोग किया जाना चाहिए। घटक वर्गों को एक कंटेनर में पंजीकृत किया जाना चाहिए क्योंकि मॉड्यूलर वातावरण में अन्यथा कोई एकल स्थान नहीं है जहां उन्हें एक्सेस किया जा सकता है। घटक वर्गों को उनके नामों के बिना उन्हें स्पष्ट रूप से निर्दिष्ट किए बिना पहचाना नहीं जा सकता क्योंकि 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 का उपयोग भी डीबगिंग को लाभ देता है।


धन्यवाद! यह कंपोनेंट साफ और अच्छा है :)
लियोन गैबन

10

मुझे एक नया उपाय सूझा। ध्यान दें कि मैं ईएस 6 मॉड्यूल का उपयोग कर रहा हूं इसलिए मुझे कक्षा की आवश्यकता है। आप इसके स्थान पर एक नया प्रतिक्रिया वर्ग भी परिभाषित कर सकते हैं।

var components = {
    example: React.createFactory( require('./ExampleComponent') )
};

var type = "example";

newComponent() {
    return components[type]({ attribute: "value" });
}

1
@klinore क्या आपने defaultविशेषता तक पहुँचने का प्रयास किया ? अर्थात: ('./ ExampleComponent') की आवश्यकता है। डिफ़ॉल्ट?
खान हुआ

7

यदि आपके घटक वैश्विक हैं तो आप बस कर सकते हैं:

var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});


1
यह खूबसूरती से काम करता है, खासकर अगर रेल का उपयोग कर। स्वीकृत उत्तर मेरे लिए काम नहीं करता है, क्योंकि Componentsसरणी परिभाषित नहीं है।
वादिम

3
वैश्विक स्तर पर (यूके) को मनमाने ढंग से नामित वस्तुओं को संलग्न करने के बजाय, आपको एक घटक रजिस्ट्री को बनाए रखने पर विचार करना चाहिए जिसे आप पंजीकृत कर सकते हैं और फिर आवश्यकता होने पर घटक संदर्भ प्राप्त कर सकते हैं।
स्लैशवाटर

6

एक आवरण घटक के लिए, एक सरल समाधान सिर्फ 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 })
    )
  }
}

मैं वास्तव में मेरी परियोजना में एक ही उद्देश्य के साथ एक घटक है)
Dziamid

2

घटक नक्शे के साथ सभी विकल्पों के पार मुझे 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/>
}

1

एक नक्शा होने से बड़ी मात्रा में घटकों के साथ अच्छा नहीं लगता है। मैं वास्तव में हैरान हूं कि किसी ने भी इस तरह का सुझाव नहीं दिया है:

var componentName = "StringThatContainsComponentName";
const importedComponentModule = require("path/to/component/" + componentName).default;
return React.createElement(importedComponentModule); 

यह वास्तव में मेरी मदद करता है जब मुझे एक बहुत बड़ी मात्रा में घटकों को प्रस्तुत करने की आवश्यकता होती है जो कि एक प्रकार की जसन सरणी के रूप में भरी हुई है।


यह मेरे लिए काम करने के करीब है, और मुझे सही दिशा में ले गया। React.createElement(MyComponent)सीधे आह्वान करने की कोशिश में त्रुटि हुई। विशेष रूप से, मैं नहीं चाहता कि माता-पिता को आयात करने के लिए सभी घटकों का पता होना चाहिए (मानचित्रण में) - क्योंकि यह एक अतिरिक्त कदम की तरह लगता है। इसके बजाय, मैंने इस्तेमाल किया const MyComponent = require("path/to/component/" + "ComponentNameString").default; return <MyComponent />
semaj1919

0

हमें लगता है कि हम गतिशील घटक लोडिंग के साथ विभिन्न विचारों को एक्सेस करना चाहते हैं। निम्नलिखित कोड एक यूआरएल के खोज स्ट्रिंग से पार्स स्ट्रिंग का उपयोग करके इसे पूरा करने का एक उदाहरण देता है।

मान लें कि हम इन 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'));

0

मान लें कि हमारे पास flagकोई है stateया नहीं props:

import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';

~~~

const Compo = flag ? ComponentOne : ComponentTwo;

~~~

<Compo someProp={someValue} />

Compoकिसी एक के साथ फ़्लैग फिल के साथ ComponentOneया ComponentTwoफिर Compoरिएक्ट कंपोनेंट की तरह काम कर सकता है।


-1

मैंने थोड़ा अलग दृष्टिकोण का उपयोग किया, क्योंकि हम हमेशा अपने वास्तविक घटकों को जानते हैं इसलिए मैंने स्विच केस को लागू करने के लिए सोचा। इसके अलावा कुल घटक मेरे मामले में 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} />

    }
  }

बस फिर से इस पार आ गया। इसे करने का यही तरीका है। आप हमेशा अपने घटकों को वैसे भी जानते हैं, और उन्हें लोड करने की आवश्यकता होती है। तो यह एक बेहतरीन उपाय है। धन्यवाद।
जेक

-1

संपादित करें: अन्य उत्तर बेहतर हैं, टिप्पणियां देखें।

मैंने इस समस्या को इस तरह हल किया:

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

3
आप शायद ऐसा नहीं करना चाहते हैं क्योंकि React.createElementआपके लुकिंग ऑब्जेक्ट में प्रत्येक घटक के लिए इनवॉइस किया जाएगा, भले ही उनमें से केवल एक ही समय में प्रदान किया जा रहा हो। इससे भी बदतर, renderमूल घटक की विधि में लुकअप ऑब्जेक्ट डालकर , यह माता-पिता को प्रदान किए जाने पर हर बार फिर से करेगा। शीर्ष उत्तर उसी चीज को प्राप्त करने का एक बेहतर तरीका है।
इंकलिंग

2
@ इंकलिंग, मैं सहमत हूं। यह तब था जब मैं सिर्फ रिएक्ट के साथ शुरुआत कर रहा था। मैंने यह लिखा था, तब यह सब भूल गया जब मैं बेहतर जानता था। यह बात बताने के लिए धन्यवाद।
हम्माद अख्वांड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.