Dynamically Rendering a React component - javascript

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?

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

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/

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

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.

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;

Related

How to create a component with hove in react js?

I'm trying to create a component that change when someone hover over it and let a img appear but I don't know whats wrong with my code, I'm not getting any error in the console but the img isn't showing. Here's my code:
var React = require('react');
var ReactDOM = require('react-dom');
var Troll = {
title: 'Why so serious?',
src: '../imagenes/troll.png'
};
var Common = React.createClass({
handleHover: function() {
return (
<img src={Troll.src} id='cara'/>
);
},
render: function () {
return (
<div onMouseEnter={this.handleHover}>
<h2>{Troll.title}</h2>
</div>
);
}
});
ReactDOM.render(
<Common />,
document.getElementById('app')
);
You can only return JSX in a render function, but you are trying to do it in an event. Your handleHover method should contain just the logic to replace the markup that is being rendered, not the markup itself.
The function handleHover must not return anything. It just need to show/hide the image.
Check this code:
class Avatar {
render () {
return (
<div
className="avatar"
onMouseOver={this.showImage.bind(this)}
onMouseLeave={this.hideImage.bind(this)}>
<figure ref="image">
<img src={this.props.img}/>
</figure>
<p>John Doe</p>
</div>
)
}
showImage () {
this.refs.image.classList.add('visible');
}
hideImage () {
this.refs.image.classList.remove('visible');
}
}
const node = document.getElementById('comp');
ReactDOM.render(
<Avatar
img="http://www.material-ui.com/images/uxceo-128.jpg"
/>,
node
);
We are just binding methods to mouseover and mouseleave events. The first method just show the image adding a CSS class, and the other method remove this class to hide it.
Click here to see this code running.
As mentioned in other answers, you don't need to return anything. Try using React state to solve this instead:
var React = require('react');
var ReactDOM = require('react-dom');
var Troll = {
title: 'Why so serious?',
src: '../imagenes/troll.png'
};
var Common = React.createClass({
getInitialState: function() {
return {
showTrollImage: false
}
},
handleHover: function() {
this.setState({ showTrollImage: true });
},
render: function () {
var trollImage = null;
if (this.state.showTrollImage) {
trollImage = <div><img src={Troll.src} id="cara" /></div>;
}
return (
<div onMouseEnter={this.handleHover}>
<h2>{Troll.title}</h2>
{trollImage}
</div>
);
}
});
ReactDOM.render(
<Common />,
document.getElementById('app')
);
And BTW, try to update your code to use ES6. See here for an example of what modern React code looks like. I'll convert your Common component:
class Common extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
showTrollImage: false,
};
}
handleHover = () => {
this.setState({ showTrollImage: true });
};
render() {
let trollImage = null;
if (this.state.showTrollImage) {
trollImage = <div><img src={Troll.src} id="cara" /></div>;
}
return (
<div onMouseEnter={this.handleHover}>
<h2>{Troll.title}</h2>
{trollImage}
</div>
);
}
});
Note that this syntax:
handleHover = () => { };
is Babel class property transformation, and you'll need to install Babel stage 2 support in your project to use this.

react-redux get width of component's parent div

This is part of the component :
import MyComp from '../../lib/MyComp'
const Data = ( { data } ) => (
<div className="data-box" id="data-box">
<MyComp data={data} />
</div>
)
How do I get the width of the data-box div inside MyComp container?
Check this working demo: JSFiddle:
var Parent = React.createClass({
render: function() {
return <div id="parent">Hello Parent<Child></Child></div>;
}
});
var Child = React.createClass({
componentDidMount: function() {
alert('Parent width: ' + this.refs.child.parentNode.clientWidth);
},
render: function() {
return <div ref="child">Hello Child</div>;
}
});
Stating ref="child" will make the element accessable by the component itself, through this.refs.child. It is the vallina node instance. Using this.refs.child.parentNode.clientWidth will return the parent's width. Or, use this.refs.child.parentNode.getBoundingClientRect().
Reference: React refs
You need to use react refs.
on your MyComp class:
class MyComp extends React.Component {
//All your PropTypes and functions...
//New function
newFunction () {
console.log(this.refs.refName);
//This will give you the Data component. There you can call methods to calculate width, or whatever you need to do with that component
}
//Your render function
render() {
return <div ...whatever you have... ref="refName">
}
}
You can check react documentation
what should work is something like this
MyComp could look like this
render() {
return <div ref="node"></div>
}
with this.refs.node you get the current dom element and with
this.res.node.parentNode
you should get the parentNode

Calling a method of a parent component from child - React Native

I'm developing my first app and still learning the flow.
So suppose I have a component called:
Parent which holds a method HelloWorld() like the following example:
import React, { Component } from 'react';
class Parent extends Component {
Helloworld() {
console.log('Hello world');
}
render () {
return (
<View>{this.props.children}</View>
)
}
}
module.exports = Parent;
and then i want to import this in to another component and use its method then how do I do it?
Ill write another short example of how I would implement it.
import React, { Component } from 'react';
import { Parent } from 'path to parent';
//or
const Parent = require('path to parent');
//which of these is better?
class Home extends Component {
Helloworld() {
console.log('Hello world');
}
render () {
return (
<Parent>
// this is what i need
<Button onClick={parent.Helloword()}>Some Button</Button>
</Parent>
)
}
}
module.exports = Home;
Thank you in advanced for your help.
Usually you should pass info from parent to child through props.
parent.jsx:
import Child from './child';
class Parent extends Component {
constructor(props) {
super(props);
this.helloWorld = this.helloWorld.bind(this);
}
helloWorld() {
console.log('Hello world!');
}
render() {
return (
<View><Child method={this.helloWorld} /></View>
);
}
}
child.jsx:
class Child extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Button onClick={this.props.method} />
);
}
}
Edit: about preference between import and require, I believe it's a matter of taste, but I think import is cleaner.
You can read React Native-Tutorial-What's going on here? about import. and here
We can pass a prop in the child class:
And then call it from the child: this.props.propName()
We can pass string, numbers, functions, array, objects in prop
import React from 'react';
import {
View,
Text,
} from 'react-native';
var Parent = React.createClass({
render: function() {
return (
<Child foo={()=>this.func1()} bar={()=>this.func2()} />
);
},
func1: function(){
//the func does not return a renderable component
console.log('Printed from the parent!');
}
func2: function(){
//the func returns a renderable component
return <Text>I come from parent!</Text>;
}
});
var Child = React.createClass({
render: function() {
this.props.foo();
return (
<Text>Dummy</Text>
{this.props.bar()}
);
},
});
module.exports = Parent;

How can I inject a common code in components in React

For multiple React component , I want to inject a common code to the life cycle of React.
Is there something good way?
var ComponentA = React.createClass({
componentWillMount: function () {
},
componentDidUpdate: function(){
//inject common code
},...
var ComponentB = React.createClass({
componentWillMount: function () {
},
componentDidUpdate: function(){
//inject common code
},...
Do you mean just sharing functions across multiple components? If so, you can just keep them in a separate file and import them where ever you need to:
// common js
function hello() {
console.log('hello');
}
module.exports = hello;
// your component
var hello = require('./common');
var ComponentA = React.createClass({
componentDidUpdate: function(){
hello();
},//...
http://www.webpackbin.com/Nk80m1x_W
Another thing you can do is create a wrapper (higher order) component:
var WrapperComponent = React.createClass({
componentDidUpdate: function() {
// code you want to inject.
},
render: function () {
return(<div>{this.props.children}</div>);
}
});
then whenever you need to use a component with that lifecycle, you can do this in jsx:
<WrapperComponent>
<ComponentA />
</WrapperComponent>
Though higher order component approach suggested by #jzm is better, you could also use mixins:
var myMixin = {
componentWillMount: function(){
//common code
},
componentDidUpdate: function(){
//common code
}
};
var ComponentA = React.createClass({
mixin: [myMixin]
});
var ComponentB = React.createClass({
mixin: [myMixin]
})

react.js: removing a component

I'm fairly new at react.js, so any help is greatly appreciated.
I have this: https://jsfiddle.net/rzjyhf91/
Wherein I have made 2 components: an image and a button.
The goal is to remove the image with a click of the button, I use unmountComponentAtNode for that, but it does not work:
var App = React.createClass({
render: function() {
return (
<div><MyImage /><RemoveImageButton /></div>
);
}
});
var MyImage = React.createClass({
render: function() {
return (
<img id="kitten" src={'http://placekitten.com/g/200/300'} />
);
}
});
var RemoveImageButton = React.createClass ({
render: function() {
return (
<button onClick={this.handleClick}>remove image</button>
)
},
handleClick: function(){
React.unmountComponentAtNode(document.getElementById('kitten'));
}
});
React.render(<App />, document.body);
How can I remove a react component from another component?
Well, it seems you should rethink how the display control is handled. React is all about isolated components, and so, you shouldn't be unmounting a component that is mounted by a parent component. Instead, you should use a callback passed down through props to accomplish something like that.
Your actual implementation will depend on your use case, but an updated version of your example that works is at: https://jsfiddle.net/nt99zzmp/1/
var App = React.createClass({
render: function() {
var img = this.state.showImage ? <MyImage /> : '';
return (
<div>{img}<RemoveImageButton clickHandler={this.removeImage} /></div>
);
},
getInitialState: function() {
return {
showImage: true
};
},
removeImage: function() {
this.setState({ showImage: false });
}
});
var MyImage = React.createClass({
render: function() {
return (
<img id="kitten" src={'http://placekitten.com/g/200/300'} />
);
}
});
var RemoveImageButton = React.createClass ({
render: function() {
return (
<button onClick={this.props.clickHandler}>remove image</button>
)
}
});
React.render(<App />, document.body);
Basically removing a component doesn't make sense in React, you probably still thinking jQuery ways, basically in all modern and new JavaScript libraries including React, you should manage your component using state or a route to handle these things, deleting an element or component is not a good way to do these things in React or Angular for example.
For example you can have a boolean in this case and if it's true, show your image, otherwise hide it, or even return a different element in your component.
So in this case, you have a component which will return differently depends on props or state... something like this:
////
var MyImage = React.createClass({
render: function() {
if(this.state.showImage) {
return (
<img id="kitten" src={'http://placekitten.com/g/200/300'} />
);
} else {
return<p>no image!</p>;
}
}
});
////
In this example, if you set this.state.render = false, the component will be removed from DOM:
render() {
const { render } = this.state;
if (render === false) return null;
return (<p>I am here as long as render isn't false</p>);
}

Categories