Dealing with window
in Gatsby could be a little bit tricky because two fundamental reasons:
window
object is only defined in the browser, so it will work perfectly under gatsby develop
but you will need to add a "hack" to avoid a code-breaking in the gatsby build
(because there's no window
in the Node server).
- Treating the
window
outside React ecosystem, may break the rehydration of the components. This means that React won't potentially know what components need to re-render on-demand, causing unmounted components, especially when navigating forward and backward using the browser's history.
There are a few workarounds to achieve what you're trying to do.
Gatsby, by default, provides a location
prop
in all top-level components (pages). So you can pass it to any child components at any time to change the class name based on its value:
const IndexPage = ({ location }) =>{
return <Layout>
<HamMenu location={location} />
<h1> some content</h1>
</Layout>
}
Then, in your <HamMenu>
component:
const HamMenu = ({ location })=> {
const [sidebar, setSidebar] = useState(false)
const [burger, setBurger] = useState(false)
const url = window.location.href;
const showSidebar = () => setSidebar(!sidebar)
const changeColor = () => {
if((window.scrollY >= 60) || (url.indexOf("kontakt") > -1)){
setBurger(true);
} else {
setBurger(false);
}
}
useEffect(() => {
if(typeof window !== "undefined"){
const url = window.location.href
const changeColor = () => {
setBurger(window.scrollY >= 60 || url.contains("kontakt"))
}
window.addEventListener('scroll', changeColor)
return () => {
window.removeEventListener('scroll', changeColor)
}
}
}, [])
return (
<StyledMenu>
<div>
<Link to="#" className={sidebar ? 'menu-bars open' : 'menu-bars' location.pathname.includes("your-page")? ''some-class' : 'some-other-class' } >
<FontAwesomeIcon
icon={faBars}
size="2x"
className={burger ? 'hamburger active' : 'hamburger'}
onClick={showSidebar}
/>
</Link>
</div>
I would suggest another approach to get the scroll position rather than using directly the window
, using React-based approach to avoid what I was pointing before (How to add a scroll event to a header in Gatsby).
However, I've fixed your initial approach, wrapping it inside a useEffect
with empty deps
([]
). This function will be triggered once the DOM tree is loaded, to avoid the code-breaking window
use that I was talking about. Alternatively to url.indexOf("kontakt") > -1
you may want to use url.includes("kontakt")
which is way more readable.
Regarding the rest, it's quite self-explanatory. Destructuring the location
props
you get access to a bunch of data, the pathname
property holds the page name so based on that, you can add a ternary condition wherever you want, such as location.pathname.includes("your-page") ? ''some-class' : 'some-other-class'
(includes
is more semantic in my opinion).
As you see, I've fixed your approach but I've also added a React/Gatsby-based one, choose what makes you feel comfortable.