2015-05-11 17 views
13

Ho una stringa che contiene un nome della classe (proveniente da un file json). Questa stringa indica alla mia classe Template quale layout/modello utilizzare per i dati (anche in json). Il problema è che il mio layout non viene visualizzato.Creare un'istanza di una classe React da una stringa

Home.jsx:

//a template or layout. 
var Home = React.createClass({ 
    render() { 
    return (
    <div>Home layout</div> 
    ) 
    } 
}); 

Template.jsx:

var Template = React.createClass({ 
    render: function() { 
    var Tag = this.props.template; //this is the name of the class eg. 'Home' 
    return (
     <Tag /> 
    ); 
    } 
}); 

non ottengo errori ma ho anche non vedo il layout/Casa Class. Ho controllato il props.template e questo registra le informazioni corrette. Inoltre, posso vedere l'elemento home nel DOM. Tuttavia sembra che questo:

<div id='template-holder> 
    <home></home> 
</div> 

se cambio riga seguente:

var Tag = Home; 
//this works but it's not dynamic! 

Tutte le idee, come posso risolvere questo problema? Sono sicuro che sia una semplice soluzione o sto facendo qualcosa di stupido. L'aiuto sarebbe apprezzato Mi scuso se questo è già stato chiesto (non ho potuto trovarlo).

Grazie, Ewan

risposta

9

Questo non funziona:

var Home = React.createClass({ ... }); 

var Component = "Home"; 
React.render(<Component />, ...); 

Tuttavia, questo sarà:

var Home = React.createClass({ ... }); 

var Component = Home; 
React.render(<Component />, ...); 

Quindi è semplicemente bisogno di trovare un modo per mappare tra la stringa "Home" e classe componenteHome. Un oggetto semplice funzionerà come un registro di base e potrai creare da lì se hai bisogno di più funzionalità.

var components = { 
    "Home": Home, 
    "Other": OtherComponent 
}; 

var Component = components[this.props.template]; 
+2

Grazie, speravo di evitare di avere mappe/collegamenti nel codice. Mi piacerebbe essere in grado di aggiungere modelli senza cambiare la base del codice principale. Non è possibile? – ewan

+0

@ewan È possibile creare una sorta di registro globale e registrare ogni componente quando viene creato con 'React.createClass' (ad esempio, avvolgendolo in una chiamata di funzione o qualcosa del genere), ma sarà sicuramente necessario ottenere riferimenti ai componenti effettivi . –

1

Quando si utilizza JSX è possibile eseguire il rendering di tag HTML (stringhe) o componenti di React (classi).

Quando si esegue var = Tag casa, funziona perché il compilatore JSX trasforma a:

var Template = React.createElement(Tag, {}); 

con il tag variabile nella stessa portata e di essere una classe di reagire.

var Tag = Home = React.createClass({ 
         render() { 
         return (
         <div>Home layout</div> 
         ) 
         } 
        }); 

Quando si esegue

var Tag = this.props.template; // example: Tag = "aClassName" 

si sta facendo

var Template = React.createElement("aClassName", null); 

Ma "aClassName" non è un tag HTML valido.

sguardo here

5

Se si può vivere con avere tutti i componenti in un unico modulo, allora questo funziona senza dover mappare manualmente i corsi ad un dizionario:

import * as widgets from 'widgets'; 
    var Type = widgets[this.props.template]; 
    ... 
    <Type /> 

L'istruzione import jolly è già un dizionario e il codice funziona come il registro nella risposta precedente.

In realtà, penso che si potrebbe lavorare con più moduli con una mappatura aggiuntiva:

import * as widgets from 'widgets'; 
import * as widgets2 from 'widgets2'; 

const registry = Object.assign({}, widgets, widgets2); 
const widget = registry[this.props.template]; 

Vorrei assolutamente fare questo. In effetti penso di esserlo.

1

Ho avuto lo stesso problema e ho scoperto la soluzione da solo. Non so se è la "migliore pratica", ma funziona e lo sto usando attualmente nella mia soluzione.

È possibile utilizzare semplicemente la funzione di valutazione "cattiva" per creare dinamicamente un'istanza di un componente di reazione. Qualcosa di simile:

function createComponent(componentName, props, children){ 
    var component = React.createElement(eval(componentName), props, children); 
    return component; 
} 

Poi, lo chiamano semplicemente dove si vuole:

var homeComponent = createComponent('Home', [props], [...children]); 

Se si adatta alle vostre esigenze, forse si può prendere in considerazione qualcosa di simile.

Spero che aiuti.

+0

Non considererei "eval" il male a meno che un utente non possa inserire tutto ciò che desidera. – xanderiel