0

I'm working on an app in Next.js and I'm trying to include a loading animation for the app. The animation is supposed to be three bouncing balls which correctly shows up. If I start the nextjs app with npm run dev it works correctly and as long as I refresh the same page it loads like its supposed to. But if I navigate to a different route the animation doesn't appear. The elements themselves don't appear. I'm not sure why it's not working, I've put the code below for reference.

import React from "react";
import Image from 'next/image'

import styled from "styled-components";

const Screen = styled.div`
  position: relative;
  height: 100vh;
  width: 100%;
  opacity: 0;
  animation: fade 0.4s ease-in forwards;

  @keyframes fade {
    0% {
      opacity: 0.4;
    }
    50% {
      opacity: 0.8;
    }
    100% {
      opacity: 1;
    }
  }
`;

const Balls = styled.div`
  display: flex;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);

  .ball {
    height: 30px;
    width: 30px;
    border-radius: 50%;
    background: #E60E33;
    margin: 0 60px 0 0;
    animation: oscillate 0.7s ease-in forwards infinite;
  }

  .one {
    animation-delay: 0.5s;
  }
  .two {
    animation-delay: 1s;
  }
  .three {
    animation-delay: 1.5s;
  }

  @keyframes oscillate {
    0% {
      transform: translateY(0);
    }
    50% {
      transform: translateY(20px);
    }
    100% {
      transform: translateY(0);
    }
  }
`;


function MyApp({ Component, pageProps }) {
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() =>{
    setTimeout(() => setLoading(true), 5000);
   })

  return (
    <>
      {loading ? (
        <React.Fragment>
          <Component {...pageProps} />
        </React.Fragment>
      ) : (
        <Screen>
        <div
        style={{
          display: "flex",
          position: "absolute",
          top: "35%",
          left: "48%",
          transform: "translate(-50%, -50%)"
        }}
      >
          </div>
          <Balls>
            <div className="ball one"></div>
            <div className="ball two"></div>
            <div className="ball three"></div>
          </Balls>
        </Screen>
       )}
    </>
  );
}

export default MyApp
Name123
  • 29
  • 4
  • 1
    Your loading animation depends on the `loading` state being `false` (which should be the opposite maybe?) and the state will only have that value on your app's first render. – ivanatias Oct 25 '22 at 05:00
  • i tried printing out the value of ```loading``` in the ```useEffect``` and it prints false and then true like its supposed to, so i'm pretty sure that's working. and it remains a blank page before showing the actual content, so its just that the animation doesnt appear – Name123 Oct 25 '22 at 05:09
  • Since you are trying to show this animation upon route change, you can try adding `router.asPath` in your `useEffect`'s dependency array so it will fire on route change too. Of course, don't forget to set `loading` to `false` before the `setTimeout` or your animation wouldn't show. – ivanatias Oct 25 '22 at 05:18
  • I tried that and it still doesnt work. It really only work on the first page even when I refresh it. It stops working only when I navigate away and then its gone. – Name123 Oct 25 '22 at 05:32

1 Answers1

2

You forgot to reset the loading state

  const router = useRouter()

  React.useEffect(() => {
    setLoading(false);
    setTimeout(() => setLoading(true), 5000);
   }, [router.asPath])

Make sure to add the route path as a dependency to avoid infinite loops.

and maybe think about switching the true false values? The app is loading when loading === false kinda weird...


Since styled components generate a random class name, you will get a hydration error when the class name changes between server and client. You need to add a config option in next.config.js for that.

// next.config.js
module.exports = {
  compiler: {
    // Enables the styled-components SWC transform
    styledComponents: true
  }
}

From this answer: https://stackoverflow.com/a/70429669/12914833

Chris Hamilton
  • 9,252
  • 1
  • 9
  • 26
  • Ive added the setLoading(false) line before the timeout and it still doesnt work. A blank screen shows for five seconds, so its just that the animation doesnt appear for some reason, – Name123 Oct 25 '22 at 05:38
  • Are you perhaps getting `Warning: Prop className did not match.` in the console? – Chris Hamilton Oct 25 '22 at 05:57
  • Yes, I was getting a prop classname not matching error, I edited the module exports and it works now, thank you so much! – Name123 Oct 25 '22 at 06:05
  • @Name123 no problem, I did just realize that my initial answer causes an infinite loop though : (. Added `router.asPath` as a dependency to fix. – Chris Hamilton Oct 25 '22 at 06:06