问题
I want to conditionally show and hide this button group depending on what is passed in from the parent component which looks like this:
<TopicNav showBulkActions={this.__hasMultipleSelected} />
....
__hasMultipleSelected: function() {
return false; //return true or false depending on data
}
....
var TopicNav = React.createClass({
render: function() {
return (
<div className="row">
<div className="col-lg-6">
<div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">
<button type="button" className="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
Bulk Actions <span className="caret"></span>
</button>
<ul className="dropdown-menu" role="menu">
<li><a href="#">Merge into New Session</a></li>
<li><a href="#">Add to Existing Session</a></li>
<li className="divider"></li>
<li><a href="#">Delete</a></li>
</ul>
</div>
</div>
</div>
);
}
});
Nothing is happening however, with the {this.props.showBulkActions ? 'show' : 'hidden'}. Am I doing anything wrong here?
回答1:
The curly braces are inside the string, so it is being evaluated as string. They need to be outside, so this should work:
<div className={"btn-group pull-right " + (this.props.showBulkActions ? 'show' : 'hidden')}>
Note the space after "pull-right". You don't want to accidentally provide the class "pull-rightshow" instead of "pull-right show". Also the parentheses needs to be there.
回答2:
As others have commented, classnames utility is the currently recommended approach to handle conditional CSS class names in ReactJs.
In your case, the solution will look like:
var btnGroupClasses = classNames(
'btn-group',
'pull-right',
{
'show': this.props.showBulkActions,
'hidden': !this.props.showBulkActions
}
);
...
<div className={btnGroupClasses}>...</div>
As a side note, I would suggest you to try to avoid using both show
and hidden
classes, so the code could be simpler. Most likely you don't need to set a class for something to be shown by default.
回答3:
If you are using a transpiler (such as Babel or Traceur) you can use the new ES6 "template strings".
Here is the answer of @spitfire109, modified accordingly:
<div className={`btn-group pull-right ${this.props.showBulkActions ? 'shown' : 'hidden'}`}>
This approach allows you to do neat things like that, rendering either s-is-shown
or s-is-hidden
:
<div className={`s-${this.props.showBulkActions ? 'is-shown' : 'is-hidden'}`}>
回答4:
You can use here String literals
const Angle = ({show}) => {
const angle = `fa ${show ? 'fa-angle-down' : 'fa-angle-right'}`;
return <i className={angle} />
}
回答5:
Expending on @spitfire109's fine answer, one could do something like this:
rootClassNames() {
let names = ['my-default-class'];
if (this.props.disabled) names.push('text-muted', 'other-class');
return names.join(' ');
}
and then within the render function:
<div className={this.rootClassNames()}></div>
keeps the jsx short
回答6:
Or use npm classnames. It is very easy and useful especially for constructing the list of classes
回答7:
In case you will need only one optional class name:
<div className={"btn-group pull-right " + (this.props.showBulkActions ? "show" : "")}>
回答8:
You can use ES6 arrays instead of classnames. The answer is based on Dr. Axel Rauschmayer article: Conditionally adding entries inside Array and object literals.
<div className={[
"classAlwaysPresent",
...Array.from(condition && ["classIfTrue"])
].join(" ")} />
回答9:
2019:
React is lake a lot of utilities. But you don't need any npm
package for that . just create somewhere the function classnames
and call it when you need;
function classnames(obj){
return Object.entries(obj).filter( e => e[1] ).map( e=>e[0] ).join(' ');
}
or
function classnames(obj){
return Object.entries(obj).map( ([k,v]) => v?k:'' ).join(' ');
}
example
stateClass= {
foo:true,
bar:false,
pony:2
}
classnames(stateClass) // return 'foo pony'
<div className="foo bar {classnames(stateClass)}"> some content </div>
Bonus For Inspiration
you can declare helper element and use his
(DOMTokenList)classList.toggle(class,condition)
and write something like that
const classes = document.createElement('span').classList;
function classstate(obj){
return Object.entries(obj).forEach( ([k,v]) => classes.toggle(k,v) ).value;
}
//Or
function classstate(obj){
for( let n in obj) classes.toggle(n,obj[n]);
return classes;
}
回答10:
More elegant solution, which is better for maintenance and readability:
const classNames = ['js-btn-connect'];
if (isSelected) { classNames.push('is-selected'); }
<Element className={classNames.join(' ')}/>
回答11:
you can use this:
<div className={"btn-group pull-right" + (this.props.showBulkActions ? ' show' : ' hidden')}>
回答12:
This would work for you
var TopicNav = React.createClass({
render: function() {
let _myClasses = `btn-group pull-right {this.props.showBulkActions?'show':'hidden'}`;
return (
...
<div className={_myClasses}>
...
</div>
);
}
});
回答13:
You can use this npm package. It handles everything and has options for static and dynamic classes based on a variable or a function.
// Support for string arguments
getClassNames('class1', 'class2');
// support for Object
getClassNames({class1: true, class2 : false});
// support for all type of data
getClassNames('class1', 'class2', null, undefined, 3, ['class3', 'class4'], {
class5 : function() { return false; },
class6 : function() { return true; }
});
<div className={getClassNames('show', {class1: true, class2 : false})} /> // "show class1"
回答14:
Based on the value of this.props.showBulkActions
you can switch classes dynamically as follows.
<div ...{...this.props.showBulkActions
? { className: 'btn-group pull-right show' }
: { className: 'btn-group pull-right hidden' }}>
回答15:
I would like to add that you can also use a variable content as a part of the class
<img src={src} alt="Avatar" className={"img-" + messages[key].sender} />
The context is a chat between a bot and a user, and the styles change depending of the sender, this is the browser result:
<img src="http://imageurl" alt="Avatar" class="img-bot">
回答16:
You can use if concept like this
var Count=React.createClass({
getInitialState: function()
{
var state={counter:1};
setInterval(function(){
this.setState(
{counter:this.state.counter+(this.state.counter==1000?9999999999:1)})
}.bind(this),1);
return state;
},
render:function(){
return(
<div>
Counter<br/>
{this.state.counter}
</div>
)
}
}
)
来源:https://stackoverflow.com/questions/30533171/react-js-conditionally-applying-class-attributes