1

I'm currently trying to add a side navbar slide in and out feature for my responsive site. I'm following the first animated example here.

I was able to get it working first with document.getElementById("mySidenav").style.width = "250px";. However, I would prefer not manipulating the DOM using document. I would like to be using local state and updating that. I am using JavaScript inline styling. Here is what some of the code looks like working:

openNavbar = () => {
  document.getElementById("mySidenav").style.width = "0";
};

<div style={styles.navbarMobile} onClick={this.openNavbar}>
  <NavSidebar/>
</div>

navbarMobile: {
  height: '100vh',
  width: '100%',
  position: 'fixed',
  zIndex: 11,
  top: '0',
  left: '-100%',
  overflowX: 'hidden',
  overflowY: 'hidden',
  transition: '1s',
  paddingRight: '15px',
  display: 'none',

  '@media (max-width: 992px)': {
    display: 'block',
    backgroundColor: 'white'
  }
}

Now obviously I'm doing this a little different than the example. Rather than manipulating the width, I am manipulating the left position. It works and runs smoothly. However, I am now trying to implement some local state and changing the CSS according to the local state value. Here is what I have:

this.state = {
  navOpen: false
}

openNavbar = () => {
  this.setState({navOpen: true});
};

<div style={this.state.navOpen ? {left: 0} : {left: -100%}, styles.navbarMobile} onClick={this.openNavbar}>
  <NavSidebar/>
</div>

navbarMobile: {
  height: '100vh',
  width: '100%',
  position: 'fixed',
  zIndex: 11,
  top: '0',
  left: '-100%',
  overflowX: 'hidden',
  overflowY: 'hidden',
  transition: '1s',
  paddingRight: '15px',
  display: 'none',

  '@media (max-width: 992px)': {
    display: 'block',
    backgroundColor: 'white'
  }
}

The main focus is on how to pass the ternary while also adding the other inline styling. By doing what I have above, all the css in navbarMobile gets applied. However, the ternary never runs. If I remove the styles.navbarMobile then the ternary works. Is there a way that I can run these two together? Any examples or ideas on how I should handle this?

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
Nappstir
  • 995
  • 2
  • 20
  • 38

2 Answers2

2

The problem is you're setting up your style prop wrong. Since you have a comma, it acts as the comma operator, so essentially, whatever the ternary is evaluated to, it's ignored and the navbarMobile style is always applied. The ternary operator is being evaluated, it's just the comma operator always evaluates to the rightmost operand. Instead, use spread syntax like this:

<div style={{
  ...style.navbarMobile,
  left: this.state.navOpen ? 0 : '-100%'
}}>

This will take the styles in navbarMobile and copy them, then determine left based on navOpen. Read more about spread syntax in JSX here.

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
  • This makes perfect sense. Really well explained. I'm fairly new to javascript and es6 so it is nice to have things re-explained as I forget often haha. Thank you Andrew. – Nappstir Aug 29 '17 at 03:19
  • I do have one quick question. Do you know if the ternary gets run anytime the state changes? Or is it a one time evaluation? – Nappstir Aug 29 '17 at 03:36
  • @Nappstir It runs every time state changes because the element *is rerendered* on every state change (which means the `render` method is called every time state is changed). – Andrew Li Aug 29 '17 at 03:37
0

If you use React Hooks, you can do it a lot easier now.

<li style={{ textDecoration: isDone ? "line-through" : "none" }}>
        {props.text}
 </li>
Retnuh
  • 1
  • 1
  • 1