react: Unable to render component from name string
I seem to be unable to render components using name strings. I wanted to be able to dynamically generate component name strings which have existing corresponding components that can be rendered.
Fiddle: http://jsfiddle.net/dhjxu5oL/
Instead of referencing the existing component and rendering it, React is rendering a custom element tag that is all lower case.
// HTML output
<componentname></componentname>
Very basic code that is failing:
// Main component to be rendered
var Parent = React.createClass({
render: function() {
var ChildName = 'Child';
return (
<ChildName />
);
}
});
// Dynamic subcomponent render
var Child = React.createClass({
render: function() {
return (
<div>
I am Child!
</div>
);
}
});
React.render(
<Parent/>,
document.body
);
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 1
- Comments: 17 (4 by maintainers)
Simple fix: just use
Child
instead of'Child'
– you want to pass an actual reference to the JS variable:http://jsfiddle.net/dhjxu5oL/1/
@af7 If that’s what you want then you need to provide the mapping yourself, there is nothing React can do for you here. React works with regular classes and classes are not magically registered with React.
@spicyj I don’t think that’s what he is asking. I think he wants to be able to create a React element from a dynamically acquired name (string).
What he is looking for is:
instead of what he has (
<ChildName />
)What @syranide said. Then in render you can do:
I came twice in a situation that I needed a dynamic use of the proper component.
A suggestion below:
The React team could create a helper function, for example: React.getComponentByName(name: string), that returns the component that has the same name as the input string:
In that way, we can easily implement the following use case of rendering the proper component based on props received:
Then, in JSX:
React.createElement(ChildName, null)
and<ChildName />
are equivalent.From @rmoskal said, I’ve been able to put something together. I’m also using
react-rails
but with a different setup you can find here if you’re on Rails as well it will allow you use import statements and use npm packages : Rails + Browserify + React + ES7I created a
selectr_option_templates
file where I will put the different components I want to use as templates which looks like this :The important part then is to use
module.exports
to make the mapping happen.Then in your parent module you can do :
I pass “ProductColor” in my
this.props.optionComponent
This way I can get my class name from the props, previously set withreact_component
helper withreact-rails
. Obviously this will work however you get your string class name from.This is the best solution I found so far, also for some reason
eval(this.props.optionComponent)
throws an error so I can’t use it.As you probably know, it’s best practice not to use
eval
or look up globals onwindow
by string name as it tends to make code hard to reason about, but you can use those patterns with React too:The key is to use a capitalized variable name (
Component
) or else React will treat it as a built-in DOM element.If you can live with having all your components in one module, then this works pretty well:
Maybe you can do something like
which isn’t a large overhead but is more reasonable than using globals. React tries to be simple and get out of your way instead of adding a lot of magic – you can then build whatever you want on top, just as you can in JS without React.
@spicyj @jsfb Both of those suggestions arrive at the same outcome. Neither of them are supporting the ability to dynamically generate name strings which reference existing components.
I wanted to store some ID value in a component prop and then use the name string to render the component.
What I am looking for is something almost like eval() or running
window[nameString]()
.Updated fiddle with easy testing: http://jsfiddle.net/q3zwtosw/