Skip to content
Advertisement

React Using addEventListener(“scroll”, function()) and useState shows no transition

I want to change background color of navigation gradually with transition like this
Article.js

import React, { useRef, useEffect } from 'react';
import Grid from '@mui/material/Grid';
import { Link as RouterLink } from "react-router-dom";
import Typography from '@mui/material/Typography';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';
import './Article.css';


export default function Article() {
  const [isScrolling, setScrolling] = React.useState(false);

  useEffect(() => {
    function handleScroll() {
      if (window.scrollY < 10) {
        setScrolling(false);
      } else {
        setScrolling(true);
      }
    }
    window.addEventListener("scroll", handleScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [isScrolling]);

  function CreateBasicBreadcrumbs() {
    return (
      <div
        role="presentation"
        className={`pop-up ${isScrolling && 'active'}`}
      >
        <Breadcrumbs
          aria-label="breadcrumb"
          sx={{ marginLeft: 2, }}
        >
          <Link
            underline="hover"
            color="inherit"
            component={RouterLink}
            to={'/'}
          >
            Home
          </Link>
          <Typography color="text.primary">
            Articles
          </Typography>
        </Breadcrumbs>
      </div >
    );
  }

  return (
    <Grid
      container='true'
      direction='row'
      width='100%'
      sx={{
        paddingTop: 5,
        backgroundColor: 'rgb(248, 249, 250)'
      }}
      onScroll={(e) => { console.log('scrolling') }}
    >
      <Grid
        item='true'
        xs={12}
        sm={12}
        md={12}
        lg={9}
        xl={7}
        sx={{
          paddingLeft: 5,
          height: '2000px',
        }}
      >
        <CreateBasicBreadcrumbs />
      </Grid>
    </Grid>
  );
}

Article.css

.pop-up {
  padding-bottom: 20px;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  position: sticky;
  top: 10px;
  transition: all 1s linear;
}

.pop-up.active {
  background-color: rgb(255, 255, 255);
}

When I run these, class name ‘active’ is added to the [div] but its background color is changed quickly from rgb(248, 249, 250) to rgb(255, 255, 255).
I think this is because addEventListener changes isScrolling every scroll and rerenders the [div] element and its children. But I’m not sure.
Could you tell me what I am doing wrong?

Advertisement

Answer

You should not define a Component like CreateBasicBreadcrumbs inside another component. If you do so, React thinks it is a different object on every render of Article, so CreateBasicBreadcrumbs will be unmounted before every rerender of Article, losing its state.

Simply move its definition outside Article, and pass isScrolling as prop down to it.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement