Search code examples
javascriptreactjsmaterial-uisetintervalfade

MaterialUI text fade with useEffect and setInterval


I am using MaterialUI's Fade component to simulate a text carousel that comes in and out according to the provided array in a prop called dataArray. I am using setIntervals to keep switching the boolean of the Fade and to change the array info. The main problem is that the text switches mid transition after the first iteration of the fade. What I am trying to achieve is a smooth fade transition and info switching loop according to the provided array while the text is hidden. I tried using async, but that does not seem to work on setIntevals.

Here is my component:

import React, { useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Paper, Fade } from '@material-ui/core';
import './FadeCarousel.css';

const useStyles = makeStyles((theme) => ({
  root: {
    backgroundColor: 'black',
  },
  paper: {
    margin: theme.spacing(1),
    backgroundColor: 'rgba(0,0,0,0)',
    color: '#f4dfc0',
    padding: '1vw 0vw 1vw 0vw',
    fontFamily: 'Chenier',
    fontSize: '2vw',
  },
}));

const FadeCarousel = ({ dataArray }) => {
  const classes = useStyles();
  const [checked, setChecked] = React.useState(true);
  const [carouselData, setCarousel] = React.useState(dataArray[0]);

  useEffect(() => {
    var count = 0;
    // Interval Fade
    setInterval(() => {
      setChecked((prev) => !prev);
    }, 5000);
    // Interval Change Data
    setInterval(() => {
      if (count == dataArray.length - 1) {
        count = 0;
      } else count++;
      setCarousel(dataArray[count]);
    }, 8000);
  }, []);

  return (
    <div className={classes.root}>
      <Fade
        in={checked}
        timeout={{
          enter: 3000,
          exit: 3000,
        }}
      >
        <Paper elevation={4} className={classes.paper}>
          {carouselData}
        </Paper>
      </Fade>
    </div>
  );
};

export default FadeCarousel;

Solution

  • Your count should change after the Fade goes through its exit cycles to have it change at the moment that the fade is on its "dark" phase.

    That means that your timings should be as follows:

    intervalFade = X

    intervalChangeData = 2*X

    Fade timeout = {enter: 2*X, exit: 2*X}

    Example here

    Code result:

    import React, { useEffect } from 'react';
    import { makeStyles } from '@material-ui/core/styles';
    import { Paper, Fade } from '@material-ui/core';
    
    const useStyles = makeStyles((theme) => ({
      root: {
        backgroundColor: 'black',
      },
      paper: {
        margin: theme.spacing(1),
        backgroundColor: 'rgba(0,0,0,0)',
        color: '#f4dfc0',
        padding: '1vw 0vw 1vw 0vw',
        fontFamily: 'Chenier',
        fontSize: '2vw',
      },
    }));
    
    const FadeCarousel = ({ dataArray }) => {
      const classes = useStyles();
      const [checked, setChecked] = React.useState(true);
      const [carouselData, setCarousel] = React.useState(dataArray[0]);
    
      const fadeTime = 1000
    
      useEffect(() => {
        var count = 0;
        // Interval Fade
        setInterval(() => {
          setChecked((prev) => !prev);
        }, fadeTime);
        // Interval Change Data
        setInterval(() => {
          if (count == dataArray.length - 1) {
            count = 0;
          } else count++;
          setCarousel(dataArray[count]);
        }, fadeTime*2);
      }, []);
    
      return (
        <div className={classes.root}>
          <Fade
            in={checked}
            timeout={{
              enter: fadeTime*2,
              exit: fadeTime*2,
            }}
          >
            <Paper elevation={4} className={classes.paper}>
              {carouselData}
            </Paper>
          </Fade>
        </div>
      );
    };
    
    export default FadeCarousel;