Reputation: 411
I need to display a header element in a React render
method where the level is dynamically set in the constructor:
class HeaderComponent extends React.Component {
constructor(props){
super(props);
this._checkedDepth = Math.min(6, props.depth)
}
render(){
return(<h{ this._checkedDepth }>{ this.props.name }</h{ this._checkedDepth }>)
}
}
ReactDOM.render(
<HeaderComponent name="Header 1" depth="2"/>,
document.getElementById('app')
);
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
This should render <h2>Header 1</h2>
with name="Header 1"
and depth=2
, but I get an error instead:
Uncaught Error: Cannot find module "./HeaderComponent"
What am I overlooking?
I'm using React 15.4.1
, babel-preset-es2015 6.9.0
, babel-preset-react 6.5.0
and running it in Chrome 55
.
Upvotes: 5
Views: 4327
Reputation: 21161
Maybe a bit too late, but you can create a component or tag dynamically without using React.createClass
with JSX putting the tag name in a variable and using that variable as you would with any other component.
In your case, inside render
, you should have something like:
const TitleTag = `h{ this._checkedDepth }>`;
return <TitleTag>{ this.props.name }</TitleTag>
Note the first character of that variable must be uppercase in order to let React know that's a React component, otherwise a tag with the exact same name (not value) of your variable will be inserted instead.
See https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized:
When an element type starts with a lowercase letter, it refers to a built-in component like
<div>
or<span>
and results in a string'div'
or'span'
passed toReact.createElement
. Types that start with a capital letter like<Foo />
compile toReact.createElement(Foo)
and correspond to a component defined or imported in your JavaScript file.We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.
There's no way to do this without creating that variable, so trying to do it on the fly as you do in your code will not work (compiler limitation).
Here's a fully working example:
class HeaderComponent extends React.Component {
constructor(props) {
super(props);
const depth = Math.max(Math.min(parseInt(props.depth) || 1, 6), 1);
this.state = { depth };
}
onClick() {
let depth;
do {
depth = Math.floor(Math.random() * 6) + 1;
} while(depth === this.state.depth);
this.setState({ depth });
}
render() {
const Title = `h${ this.state.depth }`;
return <Title className="title" onClick={ () => this.onClick() }>{ this.props.name }</Title>;
}
}
ReactDOM.render(
<HeaderComponent name="Click Me!" depth="1"/>,
document.getElementById('app')
);
body { margin: 0; }
h1 { font-size: 4rem; }
h2 { font-size: 3.5rem; }
h3 { font-size: 3rem; }
h4 { font-size: 2.5rem; }
h5 { font-size: 2rem; }
h6 { font-size: 1.5rem; }
.title {
margin: 0;
padding: 0 .5rem;
cursor: pointer;
user-select: none;
}
.title:hover {
background: #FFA;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Upvotes: 4
Reputation: 1017
Each JSX element is just syntactic sugar for calling React.createElement(component, props, ...children). So, anything you can do with JSX can also be done with just plain JavaScript. - https://facebook.github.io/react/docs/react-without-jsx.html
So you can do something like this:
render() {
return React.createElement(`h${this._checkedDepth}`, this.props)
}
Upvotes: 4