Amy Groshek
Amy Groshek

Reputation: 808

Conditional className not updated when boolean updated

I know this should be stupid simple. All of the examples I can find on here are stupid simple. But for some reason I can't get a className to change conditionally in my component.

I'm trying to animate the site logo when the user scrolls down. fullLogo is changing as expected according to the logs. But the class never changes. The only thing I can think is that once the render happens that's it, and it needs to be declared as a class in order to re-render like that. Is that the issue?

  const headerHeight = 89
  let fullLogo = true

  window.addEventListener('scroll', (e) => {
    if (window.pageYOffset > headerHeight) {
      console.log('scrolled beyond header height')
      fullLogo = false;
    } else {
      fullLogo = true;
    }
    console.log('fullLogo', fullLogo)
  })
<header className={(!!fullLogo ? 'full-logo' : '')}>

Here's the full component if that helps:

import React, { useState } from "react"
import PropTypes from "prop-types"
import {
  Collapse,
  Navbar,
  NavbarToggler,
  NavbarBrand,
  Nav,
  NavItem,
  NavLink
} from 'reactstrap'

import "./header.scss"

const Header = ({ siteTitle, menu, location }) => {

  const [isOpen, setIsOpen] = useState(false);
  const toggle = () => setIsOpen(!isOpen);

  const headerHeight = 89
  let fullLogo = true

  window.addEventListener('scroll', (e) => {
    if (window.pageYOffset > headerHeight) {
      console.log('scrolled beyond header height')
      fullLogo = false;
    } else {
      fullLogo = true;
    }
    console.log('fullLogo', fullLogo)
  })

  menu.forEach((item, index) => {
    if (item.path === location.pathname) {
      item.active = true
    } else {
      item.active = false
    }
  })

  return (
    <header className={(!!fullLogo ? 'full-logo' : '')}>
      <Navbar color="light" light expand="md" fixed="top">
        <NavbarBrand href="/">
          <span className="initial">L</span>
          <span className="rest">OGO</span>
          <span className="splitter"></span>
          <span className="initial">N</span>
          <span className="rest">AME</span>
        </NavbarBrand>
        <NavbarToggler onClick={toggle} />
        <Collapse isOpen={isOpen} navbar>
          <Nav className="mr-auto" navbar>
            {menu.map((item, index) => (
              <NavItem key={`nav_link_${index}`}>
                <NavLink href={item.path} className={item.active ? `active` : null}>{item.title}</NavLink>
              </NavItem>
            ))}
          </Nav>
        </Collapse>
      </Navbar>
    </header>
  )
}

Header.propTypes = {
  siteTitle: PropTypes.string,
  menu: PropTypes.array
}

Header.defaultProps = {
  siteTitle: ``,
  menu: {
    title: `Home`,
    path: `/`
  }
}

export default Header

Upvotes: 1

Views: 462

Answers (2)

Rahul Raj
Rahul Raj

Reputation: 342

The code by using hooks be like

import React, { useState } from "react"
import PropTypes from "prop-types"
import {
  Collapse,
  Navbar,
  NavbarToggler,
  NavbarBrand,
  Nav,
  NavItem,
  NavLink
} from 'reactstrap'

import "./header.scss"

const Header = ({ siteTitle, menu, location }) => {

  const [isOpen, setIsOpen] = useState(false);
  const toggle = () => setIsOpen(!isOpen);

  const headerHeight = 89
  const [fullLogo,setFullLogo] = useState(true)

  window.addEventListener('scroll', (e) => {
    if (window.pageYOffset > headerHeight) {
      console.log('scrolled beyond header height')
      setFullLogo(false);
    } else {
      setFullLogo(true);
    }
    console.log('fullLogo', fullLogo)
  })

  menu.forEach((item, index) => {
    if (item.path === location.pathname) {
      item.active = true
    } else {
      item.active = false
    }
  })

  return (
    <header className={(!fullLogo ? 'full-logo' : '')}> //If You Want to toggle current state
      <Navbar color="light" light expand="md" fixed="top">
        <NavbarBrand href="/">
          <span className="initial">L</span>
          <span className="rest">OGO</span>
          <span className="splitter"></span>
          <span className="initial">N</span>
          <span className="rest">AME</span>
        </NavbarBrand>
        <NavbarToggler onClick={toggle} />
        <Collapse isOpen={isOpen} navbar>
          <Nav className="mr-auto" navbar>
            {menu.map((item, index) => (
              <NavItem key={`nav_link_${index}`}>
                <NavLink href={item.path} className={item.active ? `active` : null}>{item.title}</NavLink>
              </NavItem>
            ))}
          </Nav>
        </Collapse>
      </Navbar>
    </header>
  )
}

Header.propTypes = {
  siteTitle: PropTypes.string,
  menu: PropTypes.array
}

Header.defaultProps = {
  siteTitle: ``,
  menu: {
    title: `Home`,
    path: `/`
  }
}

export default Header

Upvotes: 2

Andy Mai
Andy Mai

Reputation: 94

Your assumption is correct. There's no lifecycle event that's triggering a re-render. Functional components only update if you change props or use hooks. Here you could use a hook to setDisplayFullLogo.

Upvotes: 2

Related Questions