83

In React JSX it does not appear to be possible to do something like this:

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

I get a parse error: Unexpected token {. Is this not something React can handle?

I'm designing this component so that under the hood, the values stored in this.props.component.slug will contain valid HTML elements (h1, p, etc.). Is there any way to make this work?

5 Answers 5

100

You should not put component slug in curly braces:

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

Here is a working fiddle: http://jsfiddle.net/kb3gN/6668/

Also, you can find JSX Compiler helpful for debugging these kind of errors: http://facebook.github.io/react/jsx-compiler.html

Sign up to request clarification or add additional context in comments.

4 Comments

One gotcha I just worked out of this is that you must provide a dot in order for any other variable to be recognised i.e. var page; <page></page> won't work whereas var page = { component: component }; <page.component></page.component> does
React treats variables as custom elements if they're capitalized or have a dot notation, else HTML elements. I.e. <Page></Page> works too
had to replace React.DOM.div with 'div' for it to work
Keep in mind that your variable should hold the component itself and not just the name of the component as a string.
24

As nilgun previously pointed out, the component slug should not be wrapped in curly braces.

If you decide to store it in a variable, make sure it starts with a capital letter.

Here is an example:

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'));

Here's a working fiddle: https://jsfiddle.net/janklimo/yc3qcd0u/

2 Comments

You rock!! Variable name shall start with a capital letter. This is weird but it is what it is.
capital letter was my issue. Spent hours trying to find the solution
5

If your intention is to inject the actual component rendered, you can do something like this, which is very convenient for testing, or whatever reason you would want to dynamically inject components to render.

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

Comments

4

Edit: Maybe you forgot to add /** @jsx React.DOM */ at the beginning of js?

You can use React.DOM though:

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

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

I am not a React expert, but I think every component should be construct with a specific tag at the beginning. So it could present a clear purpose itself.

Comments

3

The solution for me was to assign the imported Component to a variable(with CapitalCase) and then render that variable.

Example:

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.