2

I'm reading Full Stack React The Complete Guide And came across this code snippet:

render() {
    if(this.props.timerIsRunning){
        return(
            <div
                className='ui bottom attached red basic button'
                onClick={this.props.onStopClick}
            >
            Stop
            </div>
        )    
    } else {
        return(
            <div
                className='ui bottom attached green basic button'
                onClick={this.props.onStartClick}
            >
            Start
            </div>
        )  
    }
} 

It uses a if statement to determine what will be rendered by the component, either a stop, or start button for a stopwatch. This example got me wondering if there was a way to do that using less space. Is there a way to create the div and then add certain properties and classes to that div depending on the value of this.props.timerIsRunning? If this weren't JSX I would propose something like this:

<div id=timerbutton></div>
<script> 
    let timerButtonDiv = document.getElementById(timerbutton)
    if(this.props.timerIsRunning) {
        timerbuttonDiv.className = 'ui bottom attached red basic 
        button'
        timerbuttonDiv.innerHTML = Stop
    } else {
        timerbuttonDiv.className = 'ui bottom attached green basic 
        button'
        timerbuttonDiv.innerHTML = Start
    }
</script>

So... let this example speak to my lack of JSX understanding, but I guess, I am just wondering if (coming from an Angular 1.X background) there is a React/JSX equivalent of ng-show or ng-class. More broadly, I am wondering where the lines are between virtual DOM and actual DOM as far as standard DOM manipulation is concerned. any resources on how React transposes JSX would certainly be helpful.

Sean Clancy
  • 661
  • 6
  • 14

2 Answers2

3

JSX lets you use {} blocks in certain places to use arbitrary JS. You could check timerIsRunning in each of these place

const running = this.props.timerIsRunning;
return (
    <div
        className={
          `ui bottom attached ${running ? "red" : "green"} basic button`
        }
        onClick={running ? this.props.onStopClick : this.props.onStartClick}
    >
    {running ? "Stop" : "Start"}
    </div>
);

or use destructuring to group things together

const {color, handler, text} = this.props.timerIsRunning ? {
    color: "red",
    handler: this.props.onStopClick,
    text: "Stop",
} : {
    color: "greed",
    handler: this.props.onStartClick,
    text: "Start",
};
return (
    <div
        className={`ui bottom attached ${color} basic button`}
        onClick={handler}
    >
    {text}
    </div>
);
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
  • This is an awesome answer! Thanks! Is that '$' before the {} part of JSX? What does it mean? I really like the use of ternary logic. It's super clean and neat. – Sean Clancy May 03 '17 at 04:01
  • The `className={}` part is JSX, everything inside those curlies is JS, so in this case that `${running ? "red" : "green"}` is the expression piece of a standard ES6 template literal: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals – loganfsmyth May 03 '17 at 04:14
  • I figured out that it's the syntax for template literals by referencing this article: http://stackoverflow.com/questions/27678052/what-is-the-usage-of-the-backtick-symbol-in-javascript Thanks again. – Sean Clancy May 03 '17 at 04:18
0

The equivalent of ng-show will be React conditional rendering.

The equivalent (kinda) of ng-class is the classnames package (not part of React) which allows you to write className props like this:

return (
    <div
        className={classnames('ui bottom attached basic button', {
          red: this.props.timerIsRunning,
          green: !this.props.timerIsRunning,
        })
        onClick={running ? this.props.onStopClick : this.props.onStartClick}
    >
    {running ? "Stop" : "Start"}
    </div>
);
Yangshun Tay
  • 49,270
  • 33
  • 114
  • 141