Home > Enterprise >  Logo does not change on scrolling using React
Logo does not change on scrolling using React

Time:03-11

Summary: I have this logo in my website header, I want this logo (image [1]) to change to another one (image [2]) on scrolling down, and to change back to the original logo (image [1]) when I scroll back to the top.

What i tried: I tried to make it with EventListener and useEffect in the header page, but I'm getting this error below:

    ERROR in src\layouts\Navbar\index.jsx
    Line 12:3:  'listenScrollEvent' is not defined  no-undef

My code:

import React, { useState } from 'react'
import { useEffect } from "react";


export default () => {

  useState = {
    imageSrc: '',
    imageAlt: ''
  }

  listenScrollEvent = e => {
    if (window.scrollY > 400) {
      this.setState({
        imageSrc: './/img/Smartlogger_logo.png',
        imageAlt: 'smartlogger white logo'
      })
    } else {
      this.setState({
        imageSrc: './../../views/Home/image/smartLoggerheader_logo.png',
        imageAlt: 'smartlogger colored logo'
      })
    }
  }

  
  useEffect(() => {
    window.addEventListener('scroll', this.listenScrollEvent)
  }, []);


  return (
    <header className='header-area header-sticky'>
      <div className='container'>
        <div className='row'>
          <div className='col-12'>
            <nav className='main-nav'>
              {/* ***** Logo Start ***** */}
              <a href='/#' className='logo'>
                <style>{css}</style>
                <img
                  src={this.setState}
                  alt='Smartlogger logo'
                />
              </a>
              {/* ***** Logo End ***** */}
              </nav>
              </div>
            </div>
          </div>
        </header>
      )
    }

CodePudding user response:

You need to make the following changes in your code. It should fix the issue.

  • Inside render() - img src replace src={this.setState} with src={this.state.imageSrc}
  • Inside listenScrollEvent function replace window.scrollY with event.srcElement.body.scrollY

it will look like this (I have used random images here):

  listenScrollEvent = event => {
    if (event.srcElement.body.scrollY > 400) {
      this.setState({
        imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
        imageAlt: 'smartlogger white logo'
      })
    } else {
      this.setState({
        imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
        imageAlt: 'smartlogger colored logo'
      })
    }
  }

Full working code : (I have added style={{height:'200vh'}} on container div just to test it on my local. You can remove it)

import React from 'react'
import { Link } from 'react-router-dom'

export default class App extends React.Component {

state = {
    imageSrc: 'https://c.tenor.com/TReUojNlZ6wAAAAi/js-javascript.gif',
    imageAlt: ''
  }

  listenScrollEvent = event => {
    if (event.srcElement.body.scrollY > 400) {
      this.setState({
        imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
        imageAlt: 'smartlogger white logo'
      })
    } else {
      this.setState({
        imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
        imageAlt: 'smartlogger colored logo'
      })
    }
  }

  componentDidMount() {
    window.addEventListener('scroll', this.listenScrollEvent)
  }

  render() {
  return (
    <header className='header-area header-sticky'>
      <div className='container' style={{height:"200vh"}}>
        <div className='row'>
          <div className='col-12'>
            <nav className='main-nav'>
              {/* ***** Logo Start ***** */}
              <a href='/#' className='logo'>
                {/* <style>{css}</style> */}
                <img
                  src={this.state.imageSrc}
                  alt='Smartlogger logo'
                />
              </a>
              {/* ***** Logo End ***** */}
          </nav>
          </div>
        </div>
      </div>
    </header>
  )
  }
}

Hope that's how you wanted it to work. Try running it on your local and then you can modify it as per your requiremnets.

CodePudding user response:

In your useState hook you want to have your src and your alt. Remember useState return an array of 2 elements, the first is the value and the second is the setter for that value. You can use the setter in your listenScrollEvent function and you can use the value in your jsx.

You are also using a css variable in you jsx that isn't defined anywhere.

It should look something like this:

import React, { useState, useEffect } from "react";

export default () => {
    const [image, setImage] = useState({
        src: "",
        alt: "",
    });

    const listenScrollEvent = (e) => {
        if (window.scrollY > 400) {
            setImage({
                src: "../img/Smartlogger_white_logo.png",
                alt: "smartlogger white logo",
            });
        } else {
            setImage({
                src: "../img/Smartlogger_colored_logo.png",
                alt: "smartlogger colored logo",
            });
        }
    };

    useEffect(() => {
        window.addEventListener("scroll", listenScrollEvent);
    }, []);

    return (
        <header className="header-area header-sticky">
            <div className="container">
                <div className="row">
                    <div className="col-12">
                        <nav className="main-nav">
                            {/* ***** Logo Start ***** */}
                            <a href="/#" className="logo">
                                <style>{css}</style>
                                <img src={require(image.src)} alt={image.alt} />
                            </a>
                            {/* ***** Logo End ***** */}
                        </nav>
                    </div>
                </div>
            </div>
        </header>
    );
};

An alternative solution that looks a little cleaner to me:

import React, { useState, useEffect } from "react";

import whiteLogo from "../img/Smartlogger_white_logo.png";
import coloredLogo from "../img/Smartlogger_colored_logo.png";

export default () => {
    const [isScrolled, setIsScrolled] = useState(false);

    const listenScrollEvent = (e) => setIsScrolled(window.scrollY > 400);

    useEffect(() => {
        window.addEventListener("scroll", listenScrollEvent);
    }, []);

    return (
        <header className="header-area header-sticky">
            <div className="container">
                <div className="row">
                    <div className="col-12">
                        <nav className="main-nav">
                            {/* ***** Logo Start ***** */}
                            <a href="/#" className="logo">
                                <style>{css}</style>
                                <img
                                    src={isScrolled ? whiteLogo : coloredLogo}
                                    alt={
                                        isScrolled
                                            ? "SmartLogger white logo"
                                            : "SmartLogger colored logo"
                                    }
                                />
                            </a>
                            {/* ***** Logo End ***** */}
                        </nav>
                    </div>
                </div>
            </div>
        </header>
    );
};

EDIT: added note about css variable, fixed typo in code and formatted better

EDIT2: fixed image link and added the require in the img src attribute, this should fix the image loading

EDIT3: added alternative solution

  • Related