Is there any required div wrapper inside a React component - javascript

I create a menu using React JS:
var Dropdown = React.createClass({
render: function() {
return (
<Title />
<OptionsDropdown />
);
}
});
where Title and OptionsDropdown are other React classes.
The problem is this code has error until I wrap them around a div like :
var Dropdown = React.createClass({
render: function() {
return (
<div class="something">
<Title />
<OptionsDropdown />
</div>
);
}
});
Is there anyway better to handle this situation when I want no div is wrapped outside Title and OptionsDropdown.

Finally. I found out there is maximum one root node in render function in React JS. Better to wrap it with a div.

Related

Error: Adjacent JSX elements must be wrapped in an enclosing tag

I am trying to print props of a react component but getting an error. Please help:
Snippet:
<!-- DOCTYPE HTML -->
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
<script src="http://fb. me/JSXTransformer-0.12.1.js"></script>
<!-- gap above is intended as else stackOverflow not allowing to post -->
</head>
<body>
<div id="div1"></div>
<script type="text/jsx">
//A component
var George = React.createClass({
render: function(){
return (
<div> Hello Dear!</div>
<div>{this.props.color}</div>
);
}
});
ReactDOM.render(<George color="blue"/>, document.getElementById('div1'));
</script>
</body>
</html>
I am expecting "Hello Dear!" and then next line "blue". But, I am getting this error instead.
Error:
React v16 and later
As of React v16 React components can return an array. This was not possible prior to v16.
Doing this is simple:
return ([ // <-- note the array notation
<div key={0}> Hello Dear!</div>,
<div key={1}>{this.props.color}</div>
]);
Note that you need to declare a key for each element of the array. According to official sources, this might become unnecessary in future versions of React, but not as of right now. Also don't forget to separate each element in the array with , as you would normally with an array.
React v15.6 and earlier
React Components can only return one expression, but you are trying to return two <div> elements.
Don't forget that the render() function is exactly that, a function. Functions always take in a number of parameters and always return exactly one value (unless void).
It's easy to forget, but you're writing JSX and not HTML. JSX is just a syntactic sugar for javascript. So one element would be translated as:
React.createElement('div', null, 'Hello Dear!');
This gives a React element, which you can return from your render() function, but you cannot return two individually. Instead you wrap them in another element which have these divs as children.
From the official docs:
Caveat:
Components must return a single root element. This is why we added a <div> to contain all the <Welcome /> elements.
Try wrapping these components in another component so that you only return one:
//A component
var George = React.createClass({
render: function(){
return (
<div>
<div> Hello Dear!</div>
<div>{this.props.color}</div>
</div>
);
}
});
ReactDOM.render(<George color="blue"/>, document.getElementById('div1'));
With React 16 we can return multiple components from render as an array (without a parent div).
return ([
<div> Hello Dear!</div>,
<div>{this.props.color}</div>
]);
Issue is you are returning more than one html element from render method, here:
return (
<div> Hello Dear!</div>
<div>{this.props.color}</div>
);
React v16+ solution:
React 16 included a new element React.Fragment, by help of that we can wrap multiple elements, and no dom node will be created for Fragment. Like this:
return (
<React.Fragment>
Hello Dear!
<div>{this.props.color}</div>
</React.Fragment>
);
or return an array:
return ([
<p key={0}>Hello Dear!</p>
<div key={1}>{this.props.color}</div>
]);
React v < 16:
Wrap all the elements in a wrapper div, like this:
return (
<div>
Hello Dear!
<div>{this.props.color}</div>
</div>
);
Reason: A React component can't return multiple elements, but a single JSX expression can have multiple children, You can only return one node, so if you have, a list of divs to return, you must wrap your components within a div, span or any other component.
One more thing, you need to include the reference of babel also, use this reference in header:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
Check the working example:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<!-- gap above is intended as else stackOverflow not allowing to post -->
</head>
<body>
<div id="div1"></div>
<script type="text/jsx">
var George = React.createClass({
render: function(){
return (
<div> Hello Dear!
<div>{this.props.color}</div>
</div>
);
}
});
ReactDOM.render(<George color="blue"/>, document.getElementById('div1'));
</script>
</body>
</html>
Wrap your returning DOM in a single html element.
Try this
return (
<div>
<div> Hello Dear!</div>
<div>{this.props.color}</div>
</div>
);
return ( <div>
<div> Hello Dear!</div>
<div>{this.props.color}</div>
</div>
);
Hi, elements inside return should be wrapped by something. Just add as shown above and should work ;)
The Render function should only return one root element try this
//A component
var George = React.createClass({
render: function(){
return (
<div>
<div> Hello Dear!</div>
<div>{this.props.color}</div>
</div>
);
}
});
Enclose everything you are using in return statement inside another div tag.
render: function(){
return (
<div>
<div> Hello Dear!</div>
<div>{this.props.color}</div>
</div>
);
}
In fact your problem is that you try to render several elements at the same time what is not possible in this version of react,
reason
render it is a function and by nature a function returns only one value
but with react-fiber you can do what you do, to correct your problem there are two solutions :
Either use a wrapper for both of your elements
var George = React.createClass ({
render: function () {
return (
<div>
<div> Hello Dear! </div>
<div> {this.props.color} </div>
<div>
);
}
});
ReactDOM.render(<George color = "blue" />, document.getElementById ('div1'));
The second solution is to return a array with both of your elements
var George = React.createClass ({
render: function () {
return ([
<div key='0'> Hello Dear! </div>,
<div key='1'> {this.props.color} </ div>
]);
}
});
ReactDOM.render (<George color = "blue" />, document.getElementById ('div1'));

How to get my handleClick to render different components

I am a beginner so please excuse my ignorance. I am posting one component from a larger app that I am building. This component has a handleClick function that changes the state when an image is clicked. When the image is clicked, a new component is rendered. Currently, the same 'new component' is rendered no matter which image is clicked. I'd like the component to be based on which image was clicked.
var AllocationDiv = React.createClass({
getInitialState: function(){
return {clicked: false};
},
handleClick: function() {
this.setState (
{clicked: true}
);
},
render: function () {
var handleFunc = this.handleClick; //because it wasn't brining this.handleClick into the render function
var chartMap = pieCharts.map(function(prop){
return <img onClick={handleFunc} id={prop} src={prop} />;
});
return (
<div id='bottomSection'>
<h2>Select Desired Asset Allocation</h2>
<div id='pieCharts'>
<table>
<tr>{pieHeadMap}</tr>
</table>
<div>
{chartMap}
<div id='test'>
{this.state.clicked ? <TestComponent /> : null}
</div>
</div>
</div>
</div>
);
}
});
var chartMap renders three images. Assuming I create three unique test components, how would I get them to be rendered depending on which image was clicked? Here is the entire app. I know the whole thing is a mess atm, but I'm using this as a sandbox to learn through problem-solving. Thanks!
http://codepen.io/sdpercussion/pen/NRQNLv?editors=0010
So, here is what I would do for this. Instead of having a boolean value for your clicked state, you should have a string. The string should be the name of the image being clicked. (you need to assign names or ID's or anything to differentiate them)
so.. initial state is:
getInitialState: function(){
return {clicked:''};
},
next your handleClick would have to change and you'd need to pass the image name/Id in to it.
handleClick: function(image) {
this.setState ({
clicked: image
});
},
then, inside your render..
(make sure to .bind(this) in your map so you can use the component scope if you want to call your methods. var self = this; type workarounds show a misunderstanding of scope)
render: function () {
var chartMap = pieCharts.map(function(prop){
// pass in your image name to your callback using bind, null value here skips over the scope portion and is what you need
return <img onClick={this.handleClick.bind(null, prop)} id={prop} src={prop} />;
}.bind(this));
// get the component you want for each specific image and save to a variable for display
var imgVar = null;
switch (this.state.image) {
case 'image1':
imgVar = <NewComponent />;
break;
case 'image2':
imgVar = <DifferentComponent />;
break;
}
return (
<div id='bottomSection'>
<h2>Select Desired Asset Allocation</h2>
<div id='pieCharts'>
<table>
<tr>{pieHeadMap}</tr>
</table>
<div>
{chartMap}
<div id='test'>
{imgVar}
</div>
</div>
</div>
</div>
);
}
You can add a dynamic "id" to your <img> tag as below. So that based on clicked image you can render a component.
handleClick: function() {
//alert(event.target.id);
if(event.target.id === "2"){
this.setState (
{clicked: true}
); }
},
render: function () {
var handleFunc = this.handleClick; //because it wasn't brining this.handleClick into the render function
var count =0;
var chartMap = pieCharts.map(function(prop){
count++;
return <img onClick={handleFunc} id={count+1} src={prop} />;
});
return (
<div id='bottomSection'>
<h2>Select Desired Asset Allocation</h2>
<div id='pieCharts'>
<table>
<tr>{pieHeadMap}</tr>
</table>
<div>
{chartMap}
<div id='test'>
{this.state.clicked ? <TestComponent /> : null}
</div>
</div>
</div>
</div>
);
}
});

How to query the px width of a div 100% width element in react.js?

I'm new to react and I'm sure I'm not the only one with this question. I have a div in my component that is width:100%; I need to calculate it's pixel width. How would I do this?
To put this in perspective of my actual use-case, here's what I'm doing:
I'm building a slider in react. My slider has a div with the class name "slide-holder" inside of this div are the individual div's for the slides. The slider is a very basic slider and the slide-holder will move horizontally the width of one slide to change to the next/previous slide.
Here is my full code - be aware I'm still working on this actively so it may break at times but you should be able to get the idea of how it works from it, I'm just doing the basics in react nothing fancy yet.
http://codepen.io/thewebtech/pen/JRXybb?editors=0110
/*var React = require("react");
var ReactDOM = require('react-dom');*/
var Slide = React.createClass({
render: function() {
return (<div className="slide" style={{backgroundImage:'url(' + this.props.imgsrc + ')'}}>
<div className="caption">{this.props.children}</div>
</div>);
}
});
var SliderControlButton = React.createClass({
render: function() {
var btnClasses="slider-control-button "+this.props.direction;
return (
<button className={btnClasses}>
{this.props.direction}
</button>
);
}
});
var SliderControls = React.createClass({
render: function() {
return (
<div className="slider-controls">
<SliderControlButton direction="left"/> <SliderControlButton direction="right"/>
</div>
);
}
});
var SliderHolder = React.createClass({
getInitialState:function(){
var setWidth= React.Children.count(this.props.children)* 200+"px";
var setSlideWidth= setWidth / React.Children.count(this.props.children);
return{width: setWidth,
slideWidth: setSlideWidth
}
},
render:function(){
return (
<div className="slide-holder" style={{width: this.state.width}}>
{this.props.children}
</div>
)
}
});
function renderChildren(props) {
return React.Children.map(props.children, child => {
if (child.type === Slide)
return React.cloneElement(child, {
name: props.name
})
else
return child
})
}
var Slider = React.createClass({
render: function() {
return (
<div className="slider">
<SliderControls/>
<SliderHolder>
<Slide imgsrc="http://jonmclarendesigns.com/wedding/wp-content/uploads/2016/09/DSC_4050.jpg">hello</Slide>
<Slide imgsrc="http://jonmclarendesigns.com/wedding/wp-content/uploads/2016/09/DSC_3819.jpg"/>
</SliderHolder>
</div>
);
}
});
ReactDOM.render(<Slider/>, document.getElementById("app"));
I realize I'm not actually answering your question directly, but I think for the actual usecase you've described, you'd be better off using some prebuilt tools.
react-css-transition-replace solves this exact problem. All you need to do is apply CSS transition classes and render the desired slide component.

Render two components adjacent to each other in React

I am trying to call a component from another component to display some html and it works if I call the component alone, but if I add more markup inside the same return function, it throws the following error:
Adjacent JSX elements must be wrapped in an enclosing tag (9:12) while parsing file
Product.jsx
var React = require('react');
var Product = React.createClass({
render: function() {
return (<p>Product</p>);
}
});
module.exports = Product;
ProductSlider.jsx (Works)
var React = require('react');
var Product = require('./Product.jsx');
var ProductSlider = React.createClass({
render: function() {
return (
<div><Product /></div>
);
}
});
module.exports = ProductSlider;
ProductSlider.jsx (Doesn't Work)
var React = require('react');
var Product = require('./Product.jsx');
var ProductSlider = React.createClass({
render: function() {
return (
<div><Product /></div>
<div><p>Something else</p></div>
);
}
});
module.exports = ProductSlider;
Does anybody knows what is wrong with this code?
You have to wrap a rendered component in a top level component, that's your problem. If you did
return (
<div>
<div><Product /></div>
<div><p>Something else</p></div>
</div>
);
It would work.
You don't need a top level <div> wrapper
If you are using react 16.2+. Simply use Fragments:
return(
<Fragment>
<div><Product /></div>
<div><p>Something else</p></div>
</Fragment>
)
You can also try this way:
return(
[
<div key="unique1"><Product /></div>
<div key="unique2"><p>Something else</p></div>
]
)
Note: key should be unique.

Build ReactJS component where siblings components need to commuicate

So I am trying to figure out the best way to structure a particular type of ReactJS Element.
So lets say I have this element called ContentArea. A ContentArea can be composed on a number of other custom elements, ContentAreaHeader, ContentAreaContent, and ContentAreaAction. ContentArea, ContentAreaHeader, and ContentAreaContent are basically wrapper elements that wrap its child in the correct HTML element with the proper classes. Implementation of ContentAreaAction is not important to this question, just wanted to mention it to show there are a number of different elements. The ContentArea should only have 1 header element but should be able to support multiple other items (ContentAreaContent and/or ContentAreaAction).
One feature is being able to click on the header and toggle the display the other elements beside the header. Coming from the AngularJS world, my initial though was to create a directive that I could just reuse so I tried that in ReactJS and my code looked this this:
var MyPage = React.createClass({
render: function() {
return (
<ContentArea>
<ContentAreaHeader>My Header</ContentAreaHeader>
<ContentAreaContent className={cssClasses.join(' ')}>My Content</ContentAreaContent>
</ContentArea>
);
}
});
Now I could add the event and collapsed state stuff this the MyPage component but then I can only have 1 ContentArea per page element or have multiple copied of that for each ContentArea, neither of which are good. In AngularJS, each component can have its own scope and inherit from its parent which would prevent this issue.
My current solution is that I have created the following mixin:
var ContentAreaCollapsableMixin = {
getInitialState: function() {
return {
collapsed: false
};
},
toggleCollapse: function() {
this.setState({
collapsed: !this.state.collapsed
});
}
}
Now to be able to have multiple ContentAreas per page elements, I create a custom ContentArea element for the needs of the page:
var MyContentArea = React.createClass({
mixins: [
contentArea.mixins.collapsable
],
render: function() {
var cssClasses = [];
console.log(this.state.collapsed);
if(this.state.collapsed) {
cssClasses.push('u-hide');
}
return (
<ContentArea>
<span onClick={this.toggleCollapse}><ContentAreaHeader>My Header</ContentAreaHeader></span>
<ContentAreaContent className={cssClasses.join(' ')}>My Content</ContentAreaContent>
</ContentArea>
);
}
});
var MyContentArea2 = React.createClass({
mixins: [
contentArea.mixins.collapsable
],
render: function() {
var cssClasses = [];
if(this.state.collapsed) {
cssClasses.push('u-hide');
}
return (
<ContentArea>
<span onClick={this.toggleCollapse}><ContentAreaHeader>My Header</ContentAreaHeader></span>
<ContentAreaContent className={cssClasses.join(' ')}>My Content</ContentAreaContent>
<ContentAreaContent className={cssClasses.join(' ')}>My Content2</ContentAreaContent>
</ContentArea>
);
}
});
var ContentAreaComponents = React.createClass({
render: function() {
return (
<div>
<h1 id="test" className="test">Content Area</h1>
<MyContentArea />
<MyContentArea2 />
</div>
);
}
});
Note I am using the span to attach my event since as far as I know I can't attach event to custom/child elements and the header should not always have this event so I don't want to pollute the header directive with that content (and maybe I might want to add that event to an icon in the header instead of the whole header).
Is this the correct way to build this type of functionality when dealing with element that are wrappers and have an hierarchy like this?
The cleanest way to do this is by passing components as props. For example:
<ContentArea
header={"My Header"}
content={[
<div>My Content</div>,
<div>My Other Content</div>
]}
/>
This looks a bit odd in JSX, so you can do it without if you prefer.
React.createElement(ContentArea, {
header: "My Header",
content: [
<div>My Content</div>,
<div>My Other Content</div>
]
})
In ContentArea you can simply render these props as you'd render props.children, but with more control.
var ContentArea = React.createClass({
getInitialState: function(){ return {open: true} },
toggleOpen: function(){ this.setState({open: !this.state.open}) },
render: function(){
var className = this.state.open ? "" : "hidden";
return (
<div>
<ContentAreaHeader onClick={this.toggleOpen}>
{this.props.header}
</ContentAreaHeader>
{this.props.content.map(function(element, index){
return (
<ContentAreaContent className={className} key={index}>
{element}
</ContentAreaContent>
);
})}
</div>
);
}
});
The resulting structure in this example would be:
<ContentArea>
<div>
<ContentAreaHeader>My Header</ContentAreaHeader>
<ContentAreaContent className="..." key="0">
<div>My Content</div>
</ContentAreaContent>
<ContentAreaContent className="..." key="1">
<div>My Other Content</div>
</ContentAreaContent>
</div>
</ContentArea>
This is the way that doesn't break any rules. The way to do it with the API you mentioned is with React.Children.map and determining if it's a header or content based on the index (e.g. 0 is the header, and 1..infinity are content), and you wrap it in a div to apply the click handler and className respectivley.

Categories

Resources