Render JSX element based on condition - javascript

So I have a simple component within a web app I have been working on and I was wondering if there is a way I could render an element within this component based on the value of this.props.item.
here is my JSX:
var React = require("react"); var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
deleteSchool: function(e){
e.preventDefault();
actions.deleteSchool(this.props.info);
},
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
<div className="panel-body">{this.props.info.tagline}</div>
</div>
)
} })
I wanted to be able to do something like this:
render:function(){
return(
code blah blah...
if (this.props.info = "nothing"){
<div className="panel-body">{this.props.info.tagline}</div>
}
...code blah blah
But I cannot write javascript withing the render function itself. Does anyone know how I could do this? Any help or advice is appreciated, thank you in advance.

You can use conditionally render using if and return the appropriate jsx
render(){
if(something){
return(<MyJsx1/>)
}else{
return(<MyJsx2/>)
}
}
You can chaage your component to:
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
{this.props.info = "nothing"?
(<div className="panel-body">{this.props.info.tagline}</div>)
:null}
</div>
)
} })
https://facebook.github.io/react/docs/conditional-rendering.html

Single line example
{(this.state.hello) ? <div>Hello</div> : <div>Goodbye</div>}
or
{(this.state.hello) ? <div>Hello</div> : false}

I often create an explicit function to to this, to avoid clutter in the main render:
var ChildComponent = React.createClass({
render: function () {
return (<p>I am the child component</p>)
}
});
var RootComponent = React.createClass({
renderChild: function () {
if (this.props.showChild === 'true') {
return (<ChildComponent />);
}
return null;
},
render: function () {
return(
<div>
{ this.renderChild() }
<p>Hello World!</p>
</div>
)
}
});

http://reactkungfu.com/2016/11/dynamic-jsx-tags/
For many React developers using JSX it is not clear how to make a
dynamic JSX tag. Meaning that instead of hardcoding whether it is
input or textarea or div or span (or anything else) we would like to
keep it in a variable.

Related

How to use the condition map function in ReactJS?

I am trying to display bootstrap carousel via ajax call using react js. Ajax receives json data consisting image name, content title and some meta information of per slide what I want to inject in DOM. So, I use the map function to generate all slides. My problem is, for the first slide I want to add a class active. But I do not know how to use condition in map().
In React, I have written: (in SliderWidget class, I have written a comment actually where I should use active class conditionally)
var HomeCarousel = React.createClass({
getInitialState: function() {
return {
data: []
}
},
componentDidMount: function() {
$.get("/api/slider", function(result) {
this.setState({
data: result
});
}.bind(this));
},
render: function() {
return (
<div id={"myCarousel"} className={"carousel slide"} data-ride="carousel">
{this.state.data.map((slider, i) => <SliderWidget key = {i} data = {slider} />)}
</div>
);
}
});
class SliderWidget extends React.Component {
render() {
return (
<div className={"item active"}> // here I want to use active class for the first slide
<img className={"first-slide"} src="images/pexels.jpeg" alt="First slide" />
<div className={"container"}>
<div className={"carousel-caption"}>
<h3>Research Indicates Breakfast is the Most Important Meal</h3>
<p><a className={"btn btn-primary"} href="#" role="button">Find Out More</a></p>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<HomeCarousel />, document.getElementById('react-home-carousel')
);
The i in the map callback is the loop index, so pass a property accordingly:
this.state.data.map( (slider, i) =>
<SliderWidget key={i} data={slider} active={i===0} />
)
Then in SliderWidget:
render() {
return (
<div className={"item" + this.props.active ? ' active' : ''}>...
)
}
Using classnames will make your life even easier.

Render new element onClick in react.js

I'm new to react and am trying to render a new element onClick:
var LoginButton = React.createClass({
..............
..............
clickHandle : function() {
this.rememberMe = {
active: localforage.getItem('rememberMe', function (err, key) {
return key;
})
};
if (this.rememberMe.active == true || this.rememberMe.active == 'checked')
{
document.getElementById('loginForm').submit();
}
else {
React.render(<wantToRemember />, document.getElementById('loginbuttonhere'));
}
return this.rememberMe.active;
},
This is the element that should appear:
var wantToRemember = React.createClass({
getInitialState : function () {
return {
position: 'absolute',
display: 'block',
top: '20px',
width: '100px',
height: '100px'
}
},
render : function () {
return (
<div className="rememberPopup" style={this.state}>
<div className="row">
<div className="staylogin">
<div className="col-md-4">
<label for="checkbox">Angemeldet bleiben</label>
</div>
<div className="col-md-1">
<input type="checkbox" id="checkbox" name="remember" />
</div>
</div>
</div>
</div>
);
}
});
but it doesn't appear, instead react renders this html:
<wanttoremember data-reactid=".1"></wanttoremember>
I'm pretty sure I'm doing some pretty basic stuff wrong, but can't figure out what. Isn't it possible to call different elements like this?
Your react.js component name begins with a lower-case letter, it should start with an upper-case leter: var WantToRemember = React.createClass(...) and React.render(<WantToRemember />,....
The JSX compiler requires for component names to begin with an upper-case letter (see jsx docs on this):
To render a React Component, just create a local variable that starts with an upper-case letter:
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.getElementById('example'));
You should pass a React element to React.render instead of the tag itself, something like this:
React.render(
React.createElement(wantToRemember)
);

Pattern for React when you optionally animate certain components

I have a few components that optionally animate based on certain state. For example, like mobile apps, if the sidebar is open and you tap a nav item in the sidebar we don't do the sliding animation between panels, but if its closed and you tap a link it slides the panels. "Panels" being pages. The code, right now, looks like:
render: function () {
var appContent;
if (this.state.sidebarOpen) {
appContent = <div className="app-content">
<this.props.activeRouteHandler ref="route" />
</div>
}
else {
appContent = <CSSTransitionGroup component={React.DOM.div}
className="app-content"
transitionName="pane-animate">
<this.props.activeRouteHandler ref="route" />
</CSSTransitionGroup>
}
return (
<div className="wrapper">
<Sidebar closeHandler={this.sidebarCloseHandler} ref="sidebar" />
<div className="inner-wrapper">
{appContent}
</div>
</div>
);
},
Having that if/else there for just changing if the section should animate or not seems gross and confusing to other developers when they come in and look at it. Is there a better pattern to this?
Will this work?
Uses JSX spreads from React v0.12.
var CSSTransitionIf = React.createClass({
render: function() {
if (this.props.test) {
return <CSSTransitionGroup {...this.props}>{this.props.children}</CSSTransitionGroup>
}
else {
var component = this.props.component
return <component className={this.props.className}>{this.props.children}</component>
}
}
})
//...
render: function () {
return <div className="wrapper">
<Sidebar closeHandler={this.sidebarCloseHandler} ref="sidebar" />
<div className="inner-wrapper">
<CSSTransitionIf test={!this.state.sidebarOpen} component={React.DOM.div}
className="app-content"
transitionName="pane-animate">
<this.props.activeRouteHandler ref="route" />
</CSSTransitionIf>
</div>
</div>
},
// ...

How to have conditional elements and keep DRY with Facebook React's JSX?

How do I optionally include an element in JSX? Here is an example using a banner that should be in the component if it has been passed in. What I want to avoid is having to duplicate HTML tags in the if statement.
render: function () {
var banner;
if (this.state.banner) {
banner = <div id="banner">{this.state.banner}</div>;
} else {
banner = ?????
}
return (
<div id="page">
{banner}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Just leave banner as being undefined and it does not get included.
What about this. Let's define a simple helping If component.
var If = React.createClass({
render: function() {
if (this.props.test) {
return this.props.children;
}
else {
return false;
}
}
});
And use it this way:
render: function () {
return (
<div id="page">
<If test={this.state.banner}>
<div id="banner">{this.state.banner}</div>
</If>
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
UPDATE: As my answer is getting popular, I feel obligated to warn you about the biggest danger related to this solution. As pointed out in another answer, the code inside the <If /> component is executed always regardless of whether the condition is true or false. Therefore the following example will fail in case the banner is null (note the property access on the second line):
<If test={this.state.banner}>
<div id="banner">{this.state.banner.url}</div>
</If>
You have to be careful when you use it. I suggest reading other answers for alternative (safer) approaches.
UPDATE 2: Looking back, this approach is not only dangerous but also desperately cumbersome. It's a typical example of when a developer (me) tries to transfer patterns and approaches he knows from one area to another but it doesn't really work (in this case other template languages).
If you need a conditional element, do it like this:
render: function () {
return (
<div id="page">
{this.state.banner &&
<div id="banner">{this.state.banner}</div>}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
If you also need the else branch, just use a ternary operator:
{this.state.banner ?
<div id="banner">{this.state.banner}</div> :
<div>There is no banner!</div>
}
It's way shorter, more elegant and safe. I use it all the time. The only disadvantage is that you cannot do else if branching that easily but that is usually not that common.
Anyway, this is possible thanks to how logical operators in JavaScript work. The logical operators even allow little tricks like this:
<h3>{this.state.banner.title || 'Default banner title'}</h3>
Personally, I really think the ternary expressions show in (JSX In Depth) are the most natural way that conforms with the ReactJs standards.
See the following example. It's a little messy at first sight but works quite well.
<div id="page">
{this.state.banner ? (
<div id="banner">
<div class="another-div">
{this.state.banner}
</div>
</div>
) :
null}
<div id="other-content">
blah blah blah...
</div>
</div>
You may also write it like
{ this.state.banner && <div>{...}</div> }
If your state.banner is null or undefined, the right side of the condition is skipped.
The If style component is dangerous because the code block is always executed regardless of the condition. For example, this would cause a null exception if banner is null:
//dangerous
render: function () {
return (
<div id="page">
<If test={this.state.banner}>
<img src={this.state.banner.src} />
</If>
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Another option is to use an inline function (especially useful with else statements):
render: function () {
return (
<div id="page">
{function(){
if (this.state.banner) {
return <div id="banner">{this.state.banner}</div>
}
}.call(this)}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Another option from react issues:
render: function () {
return (
<div id="page">
{ this.state.banner &&
<div id="banner">{this.state.banner}</div>
}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Simple, create a function.
renderBanner: function() {
if (!this.state.banner) return;
return (
<div id="banner">{this.state.banner}</div>
);
},
render: function () {
return (
<div id="page">
{this.renderBanner()}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
This is a pattern I personally follow all the time. Makes code really clean and easy to understand. What's more it allows you to refactor Banner into its own component if it gets too large (or re-used in other places).
&& + code-style + small components
This simple test syntax + code-style convention + small focused components is for me the most readable option out there. You just need to take special care of falsy values like false, 0 or "".
render: function() {
var person= ...;
var counter= ...;
return (
<div className="component">
{person && (
<Person person={person}/>
)}
{(typeof counter !== 'undefined') && (
<Counter value={counter}/>
)}
</div>
);
}
do notation
ES7 stage-0 do notation syntax is also very nice and I'll definitively use it when my IDE supports it correctly:
const Users = ({users}) => (
<div>
{users.map(user =>
<User key={user.id} user={user}/>
)}
</div>
)
const UserList = ({users}) => do {
if (!users) <div>Loading</div>
else if (!users.length) <div>Empty</div>
else <Users users={users}/>
}
More details here: ReactJs - Creating an "If" component... a good idea?
The experimental ES7 do syntax makes this easy. If you're using Babel, enable the es7.doExpressions feature then:
render() {
return (
<div id="banner">
{do {
if (this.state.banner) {
this.state.banner;
} else {
"Something else";
}
}}
</div>
);
}
See http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions
As already mentioned in the answers, JSX presents you with two options
Ternary operator
{ this.state.price ? <div>{this.state.price}</div> : null }
Logical conjunction
{ this.state.price && <div>{this.state.price}</div> }
However, those don't work for price == 0.
JSX will render the false branch in the first case and in case of logical conjunction, nothing will be rendered. If the property may be 0, just use if statements outside of your JSX.
This component works when you have more than one element inside "if" branch:
var Display = React.createClass({
render: function () {
if (!this.props.when) {
return false;
}
return React.DOM.div(null, this.props.children);
},
});
Usage:
render: function() {
return (
<div>
<Display when={this.state.loading}>
Loading something...
<div>Elem1</div>
<div>Elem2</div>
</Display>
<Display when={!this.state.loading}>
Loaded
<div>Elem3</div>
<div>Elem4</div>
</Display>
</div>
);
}
P.s. someone think that these components are not good for code reading. But in my mind, Html with javascript is worse
Most examples are with one line of "html" that is rendered conditionally. This seems readable for me when I have multiple lines that needs to be rendered conditionally.
render: function() {
// This will be renered only if showContent prop is true
var content =
<div>
<p>something here</p>
<p>more here</p>
<p>and more here</p>
</div>;
return (
<div>
<h1>Some title</h1>
{this.props.showContent ? content : null}
</div>
);
}
First example is good because instead of null we can conditionally render some other content like {this.props.showContent ? content : otherContent}
But if you just need to show/hide content this is even better since Booleans, Null, and Undefined Are Ignored
render: function() {
return (
<div>
<h1>Some title</h1>
// This will be renered only if showContent prop is true
{this.props.showContent &&
<div>
<p>something here</p>
<p>more here</p>
<p>and more here</p>
</div>
}
</div>
);
}
There is another solution, if component for React:
var Node = require('react-if-comp');
...
render: function() {
return (
<div id="page">
<Node if={this.state.banner}
then={<div id="banner">{this.state.banner}</div>} />
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
I use a more explicit shortcut: A Immediately-Invoked Function Expression (IIFE):
{(() => {
if (isEmpty(routine.queries)) {
return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
} else if (this.state.configured) {
return <DeviceList devices={devices} routine={routine} configure={() => this.setState({configured: false})}/>
} else {
return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
}
})()}
Maybe it helps someone who comes across the question: All the Conditional Renderings in React It's an article about all the different options for conditional rendering in React.
Key takeaways of when to use which conditional rendering:
** if-else
is the most basic conditional rendering
beginner friendly
use if to opt-out early from a render method by returning null
** ternary operator
use it over an if-else statement
it is more concise than if-else
** logical && operator
use it when one side of the ternary operation would return null
** switch case
verbose
can only be inlined with self invoking function
avoid it, use enums instead
** enums
perfect to map different states
perfect to map more than one condition
** multi-level/nested conditional renderings
avoid them for the sake of readability
split up components into more lightweight components with their own simple conditional rendering
use HOCs
** HOCs
use them to shield away conditional rendering
components can focus on their main purpose
** external templating components
avoid them and be comfortable with JSX and JavaScript
I made https://www.npmjs.com/package/jsx-control-statements to make it a bit easier, basically it allows you to define <If> conditionals as tags and then compiles them into ternary ifs so that the code inside the <If> only gets executed if the condition is true.
There is also a really clean one line version... { this.props.product.title || "No Title" }
Ie:
render: function() {
return (
<div className="title">
{ this.props.product.title || "No Title" }
</div>
);
}
I made https://github.com/ajwhite/render-if recently to safely render elements only if the predicate passes.
{renderIf(1 + 1 === 2)(
<span>Hello!</span>
)}
or
const ifUniverseIsWorking = renderIf(1 + 1 === 2);
//...
{ifUniverseIsWorking(
<span>Hello!</span>
)}
You can conditionally include elements using the ternary operator like so:
render: function(){
return <div id="page">
//conditional statement
{this.state.banner ? <div id="banner">{this.state.banner}</div> : null}
<div id="other-content">
blah blah blah...
</div>
</div>
}
You can use a function and return the component and keep thin the render function
class App extends React.Component {
constructor (props) {
super(props);
this._renderAppBar = this._renderAppBar.bind(this);
}
render () {
return <div>
{_renderAppBar()}
<div>Content</div>
</div>
}
_renderAppBar () {
if (this.state.renderAppBar) {
return <AppBar />
}
}
}
Here is my approach using ES6.
import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';
class ToggleBox extends Component {
constructor(props) {
super(props);
this.state = {
// toggle box is closed initially
opened: false,
};
// http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
this.toggleBox = this.toggleBox.bind(this);
}
toggleBox() {
// check if box is currently opened
const { opened } = this.state;
this.setState({
// toggle value of `opened`
opened: !opened,
});
}
render() {
const { title, children } = this.props;
const { opened } = this.state;
return (
<div className="box">
<div className="boxTitle" onClick={this.toggleBox}>
{title}
</div>
{opened && children && (
<div class="boxContent">
{children}
</div>
)}
</div>
);
}
}
ReactDOM.render((
<ToggleBox title="Click me">
<div>Some content</div>
</ToggleBox>
), document.getElementById('app'));
Demo: http://jsfiddle.net/kb3gN/16688/
I'm using code like:
{opened && <SomeElement />}
That will render SomeElement only if opened is true. It works because of the way how JavaScript resolve logical conditions:
true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise
As React will ignore false, I find it very good way to conditionally render some elements.
With ES6 you can do it with a simple one-liner
const If = ({children, show}) => show ? children : null
"show" is a boolean and you use this class by
<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>
I don't think this has been mentioned. This is like your own answer but I think it's even simpler. You can always return strings from the expressions and you can nest jsx inside expressions, so this allows for an easy to read inline expression.
render: function () {
return (
<div id="page">
{this.state.banner ? <div id="banner">{this.state.banner}</div> : ''}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpf1/t39.3284-6/10574688_1565081647062540_1607884640_n.js"></script>
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpa1/t39.3284-6/10541015_309770302547476_509859315_n.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";
var Hello = React.createClass({
render: function() {
return (
<div id="page">
{this.props.banner ? <div id="banner">{this.props.banner}</div> : ''}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
});
var element = <div><Hello /><Hello banner="banner"/></div>;
React.render(element, document.body);
}()</script>
I like the explicitness of Immediately-Invoked Function Expressions (IIFE) and if-else over render callbacks and ternary operators.
render() {
return (
<div id="page">
{(() => (
const { banner } = this.state;
if (banner) {
return (
<div id="banner">{banner}</div>
);
}
// Default
return (
<div>???</div>
);
))()}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
You just need to get acquainted of the IIFE syntax, {expression} is the usual React syntax, inside it just consider that you're writing a function that is invoking itself.
function() {
}()
that need to be wrapped inside parens
(function() {
}())
There is also a technique using render props to conditional render a component. It's benefit is that the render wouldn't evaluate until the condition is met, resulting in no worries for null and undefined values.
const Conditional = ({ condition, render }) => {
if (condition) {
return render();
}
return null;
};
class App extends React.Component {
constructor() {
super();
this.state = { items: null }
}
componentWillMount() {
setTimeout(() => { this.setState({ items: [1,2] }) }, 2000);
}
render() {
return (
<Conditional
condition={!!this.state.items}
render={() => (
<div>
{this.state.items.map(value => <p>{value}</p>)}
</div>
)}
/>
)
}
}
When having to only render something if passed condition is fullfilled, you can use syntax:
{ condition && what_to_render }
The code in this manner would look like this :
render() {
const { banner } = this.state;
return (
<div id="page">
{ banner && <div id="banner">{banner}</div> }
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
There are, of course, other valid ways to do this, it's all up to preferences and the occassion. You can learn more ways on how to do conditional rendering in React in this article if you're interested!
I just use following snippet in React with TypeScript
export default function ReactIf(props: {condition: boolean, children: React.ReactNode }) {
return props.condition ? <React.Fragment>{props.children}</React.Fragment> : <React.Fragment/>;
}
Just to add another option - if you like/tolerate coffee-script you can use coffee-react to write your JSX in which case if/else statements are usable as they are expressions in coffee-script and not statements:
render: ->
<div className="container">
{
if something
<h2>Coffeescript is magic!</h2>
else
<h2>Coffeescript sucks!</h2>
}
</div>
Just to extend #Jack Allan answer with references to docs.
React basic (Quick Start) documentation suggests null in such case.
However, Booleans, Null, and Undefined Are Ignored as well, mentioned in Advanced guide.

React dynamic events

I have difficulties to attach dynamic events to my react components. I have the following components:
var ListItem = React.createClass({
render: function() {
return (
<li className="selector" >
<div className="column">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<div>{this.props.children}</div>
</div>
</li>
);
}
});
var ListBox = React.createClass({
mixins : [MyMixin],
render : function() {
this.nodes = this.props.data.map(function(item) {
return <ListItem author={item.author}>{item.text}</ListItem>;
});
return (
<ul id="columns">
{this.nodes}
</ul>
);
}
});
As you see the ListItem has className set to "selector". Base on this "selector" I want to query nodes and attach dynamically events in the MyMixin.
React.renderComponent(
<ListBox data={data} selector="li.selector" />,
document.getElementById('example')
);
Maybe my idea is all wrong as I'm fairy new to React.
Regards
You should listen to events directly on the ListItem component. React doesn't want you to think about attaching listeners later.
var ListItem = React.createClass({
handleClick: function(event) {
// Handle ListItem click
},
handleDoubleClick: function(event) {
// Handle ListItem double click
},
render: function() {
return (
<li className="selector"
onClick={this.handleClick}
onDoubleClick={this.handleDoubleClick}>
<div className="column">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<div>{this.props.children}</div>
</div>
</li>
);
}
});
React expects the attributes to exactly match the event name. You can check out the full list of supported events to make sure you use the right names.

Categories

Resources