1

I am trying to figure out how to implement window.addEventListener in React. I'm developing a website with Gatsby and in "development" environment it works but whenever I start in production it gets an error. This is my code:

const checkHeader = () => { 
    // Detect scroll position
    let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    if (viewportWidth > 1100) {
        let scrollPosition = Math.round(window.scrollY);

        if (scrollPosition > 100){
            document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
        }
        else {
            document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
        }

    } else {

    }
};

// Run the checkHeader function every time you scroll
window.addEventListener('scroll', checkHeader);

I want to apply a class when Scroll. I've checked that I can't use "window." in React. How is the way to implement this code in React?

4
  • wats the error u get? Commented May 9, 2020 at 10:32
  • 1
    Also if u r using react.. there are chances your applied class suddenly disappears when DOM re-renders. You should modify the state in the eventlistener and set the class based on the state varaible in the rendeer. Commented May 9, 2020 at 10:33
  • Refer : stackoverflow.com/questions/38980371/… Commented May 9, 2020 at 10:43
  • usehooks.com/useOnScreen - Create an Intersection observer React Hook :) Commented May 11, 2020 at 9:10

3 Answers 3

3

During development, react components are only run in the browser where window is defined. When building, Gatsby renders these components on the server where window is not defined.

Generally with React, the solution is to only access window in componentDidMount or to check that window exists before accessing it.

const checkHeader = () => { 
    // Detect scroll position
    let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    if (viewportWidth > 1100) {
        let scrollPosition = Math.round(window.scrollY);

        if (scrollPosition > 100){
            document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
        }
        else {
            document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
        }

    } else {

    }
};

// Check that window exists before accessing it
if (typeof window !== 'undefined') {
    // Run the checkHeader function every time you scroll
    window.addEventListener('scroll', checkHeader);
}
Sign up to request clarification or add additional context in comments.

2 Comments

just missing the if statement, thank you! it works! really appreciate!
Is it a right way to use querySelector in reactjs? @ksav
1

You can directly add window events with Gatsby since it performs server side rendering. To do that you need to add you listeners in gatsby-browser.js inside onClientEntry method which is called when client is loaded

// gatsby-browser.js
// ES6


const checkHeader = () => { 
    // Detect scroll position
    let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    if (viewportWidth > 1100) {
        let scrollPosition = Math.round(window.scrollY);

        if (scrollPosition > 100){
            document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
        }
        else {
            document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
        }

    } else {

    }
};


export const onClientEntry = () => {
   // Run the checkHeader function every time you scroll
   window.addEventListener('scroll', checkHeader);
}

3 Comments

Hi Shubham, I am starting with Gatsby and I will check the gastby-browser method! any resource to learn about? thank you for your time!
gatsbyjs.org/docs/browser-apis/#onClientEntry. This is the right way to go instead of adding an if condition
Ok, I must change my site structure theme. Never work with gatby-browser before! thanks :)
0

Calling the function on did mount of the root component might solve your issue. for example:

// your entry component
const App = () => {

  React.useEffect(() => { // Will be called after mounting the componnent.
    onClientEntry();
  }, []);

  return (
    <Home />
  );
}

Hope this helps

1 Comment

thanks Vishnu for your response. I will check this method too, thank you for your time ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.