Renderizando dinámicamente un componente de React

78

En React JSX, no parece ser posible hacer algo como esto:

render: function() {
  return (
    <{this.props.component.slug} className='text'>
      {this.props.component.value}
    </{this.props.component.slug}>
  );
}

Recibo un error de análisis: token inesperado {. ¿No es esto algo que React puede manejar?

Estoy diseñando este componente para que, bajo el capó, los valores almacenados this.props.component.slugcontengan elementos HTML válidos (h1, p, etc.). ¿Hay alguna manera de hacer funcionar esto?

eriklharper
fuente

Respuestas:

96

No debe poner el componente slug entre llaves:

var Hello = React.createClass({
    render: function() {
        return <this.props.component.slug className='text'>
            {this.props.component.value}
        </this.props.component.slug>;
    }
});

React.renderComponent(<Hello component={{slug:React.DOM.div, value:'This is my header'}} />, document.body);

Aquí hay un violín que funciona: http://jsfiddle.net/kb3gN/6668/

Además, puede encontrar útil el compilador JSX para depurar este tipo de errores: http://facebook.github.io/react/jsx-compiler.html

nilgun
fuente
16
Un problema que acabo de resolver es que debe proporcionar un punto para que se reconozca cualquier otra variable, es decir var page; <page></page>, no funcionará, mientras que var page = { component: component }; <page.component></page.component>
marksyzm
5
React trata las variables como elementos personalizados si están en mayúscula o tienen una notación de puntos, de lo contrario elementos HTML. Es decir, <Page> </Page> también funciona
bebbi
tuvo que reemplazar React.DOM.div con 'div' para que funcione
galki
3
Tenga en cuenta que su variable debe contener el componente en sí y no solo el nombre del componente como una cadena .
totymedli
22

Como Nilgun señaló anteriormente, el componente slug no debe estar envuelto en llaves.

Si decide almacenarlo en una variable, asegúrese de que comience con una letra mayúscula.

Aquí hay un ejemplo:

var Home = React.createClass({
  render: function() {
    return (
      <div>
        <h3>This is an input</h3>
        <CustomComponent inputType="input" />
        <h3>This is a text area</h3>
        <CustomComponent inputType="textarea" />
      </div>
    );
  }
});

var CustomComponent = React.createClass({
  render: function() {
    // make sure this var starts with a capital letter
    var InputType = this.props.inputType;
    return <InputType />;
  }
});

React.render(<Home />, document.getElementById('container'));

Aquí hay un violín que funciona: https://jsfiddle.net/janklimo/yc3qcd0u/

Jan Klimo
fuente
¡¡Tú Molas!! El nombre de la variable debe comenzar con una letra mayúscula. Esto es extraño pero es lo que es.
Aftab Naveed
5

Si su intención es inyectar el componente real renderizado, puede hacer algo como esto, que es muy conveniente para las pruebas, o cualquier razón por la que desee inyectar componentes dinámicamente para renderizar.

var MyComponentF=function(ChildComponent){
    var MyComponent = React.createClass({
        getInitialState: function () {
            return {
            };
        },
        componentDidMount: function () {
        },
        render: function () {
            return (
                <div className="MyComponent">
                    <ChildComponent></ChildComponent>
                </div>
            );
        }
    });
    return MyComponent;
};

var OtherComponentF=function(){
    var OtherComponent = React.createClass({
        getInitialState: function () {
            return {
            };
        },
        componentDidMount: function () {
        },
        render: function () {
            return (
                <div className="OtherComponent">
                    OtherComponent
                </div>
            );
        }
    });
    return OtherComponent;
};

var AnotherComponentF=function(){
    var AnotherComponent = React.createClass({
        getInitialState: function () {
            return {
            };
        },
        componentDidMount: function () {
        },
        render: function () {
            return (
                <div className="AnotherComponent">
                    AnotherComponent
                </div>
            );
        }
    });
    return AnotherComponent;
};

$(document).ready(function () {
    var appComponent = MyComponentF(OtherComponentF());

    // OR
    var appComponent = MyComponentF(AnotherComponentF());

    // Results will differ depending on injected component.

    ReactDOM.render(React.createElement(appComponent), document.getElementById("app-container"));
});
Gudlaugur Egilsson
fuente
4

Editar : ¿Quizás olvidó agregar /** @jsx React.DOM */al principio de js?

Sin React.DOMembargo, puedes usar :

render: function() {
  return React.DOM[this.props.component.slug](null, this.props.component.value);
}

http://jsbin.com/rerehutena/2/edit?html,js,output

No soy un experto en React, pero creo que cada componente debería construirse con una etiqueta específica al principio. Entonces podría presentar un propósito claro en sí mismo.

fankt
fuente
0

La solución para mí fue asignar el Componente importado a una variable (con CapitalCase) y luego renderizar esa variable.

Ejemplo:

import React, { Component } from 'react';
import FooComponent from './foo-component';
import BarComponent from './bar-component';

class MyComponent extends Component {
    components = {
        foo: FooComponent,
        bar: BarComponent
    };

        //this is the most important step
       const TagName = this.components.foo;

    render() {
       return <TagName />
    }
}
export default MyComponent;
Juanma Menéndez
fuente