2

I'm trying to integrate CSSTransition to my Gatsby site, but it is not applying any of the classes. I'm utilizing CSS modules, and I've got a <div> that serves as the parent that fades in and out, essentially applying the fade effect to this and covering the content while it changes. It's got the class fadEffect. Here is my app-layout component, and the SASS.

AppLayout.tsx

import React, { ReactNode, useState } from 'react';

import { ApiContext } from 'contexts/ApiContext';
import { graphql, StaticQuery } from 'gatsby';
import { TransitionGroup, CSSTransition } from 'react-transition-group';

import { Devtools } from '../devtools/Devtools';
import { Footer } from '../footer/Footer';
import { Header } from '../header/Header';
import s from './AppLayout.scss';

interface AppLayoutProps {
  children: ReactNode;
  location: string;
}

const isDev = process.env.NODE_ENV === 'development';

// tslint:disable no-default-export
export default ({ children, location }: AppLayoutProps) => {
  const [fadeEffectVisible, setFadeEffectVisible] = useState(false);

  const handleFadeEffectEntered = () => {
    setTimeout(() => {
      setFadeEffectVisible(false);
    }, 50);
  };

  return (
    <StaticQuery
      query={`${NavQuery}`}
      render={(data) => (
        <>
          <ApiContext>
            <Header navigationContent={data.prismic.allNavigations.edges[0].node} />

            <CSSTransition
              in={fadeEffectVisible}
              timeout={150}
              classNames={{
                enter: s.fadeEffectEnter,
                enterActive: s.fadeEffectEnterActive,
                enterDone: s.fadeEffectEnterDone,
                exit: s.fadeEffectExit,
                exitActive: s.fadeEffectExitActive,
              }}
              onEntered={handleFadeEffectEntered}
            >
              <div className={s.fadeEffect} aria-hidden="true" />
            </CSSTransition>

            <TransitionGroup component={null}>
              <CSSTransition
                key={location}
                timeout={150}
                classNames={{
                  enter: s.pageEnter,
                }}
              >
                <div className={s.layout}>
                  {children}

                  <Footer navigationItems={data.prismic.allNavigations.edges[0].node} />

                  {isDev && <Devtools />}
                </div>
              </CSSTransition>
            </TransitionGroup>
          </ApiContext>
        </>
      )}
    />
  );
};

const NavQuery = graphql`
  query NavQuery {
    prismic {
      allNavigations {
        edges {
          node {
            ...NotificationBar
            ...NavigationItems
            ...FooterNavigationItems
          }
        }
      }
    }
  }
`;

AppLayout.scss

@import '~styles/config';

:global {
  @import '~styles/base';
}

.layout {
  display: block;
  min-height: 100vh;
}

.pageEnter {
  display: none;
}

.fadeEffect {
  display: none;
  position: fixed;
  z-index: 9;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #fff;
  transition: opacity 0.15s linear;

  &Enter {
    display: block;
    opacity: 0;
  }

  &Active,
  &Done,
  &Exit {
    display: block;
    opacity: 1;
  }

  &ExitActive {
    opacity: 0;
  }
}

I'm happy to provide more details/code if this isn't enough. I'm newish to React and Gatsby, so I'm still learning the lingo. Thanks in advance.

Jesse Winton
  • 568
  • 10
  • 33
  • I have added my suggestion as an answer if that still doesn't work, could you please share codesandbox link with issue reproduced? – Dipen Shah Sep 27 '20 at 03:08

1 Answers1

3

I don't see part of your code where you are updating fadeEffectVisible to true for first CSSTransition and I don't see in property at all on second CSSTransition and I would bet that is your issue. Please take a look at this example from React Transition Group for understanding usage of properties.

App.js

function App() {
  const [inProp, setInProp] = useState(false);
  return (
    <div>
      <CSSTransition in={inProp} timeout={200} classNames="my-node">
        <div>
          {"I'll receive my-node-* classes"}
        </div>
      </CSSTransition>
      <button type="button" onClick={() => setInProp(true)}>
        Click to Enter
      </button>
    </div>
  );
}

Style.css

.my-node-enter {
  opacity: 0;
}
.my-node-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.my-node-exit {
  opacity: 1;
}
.my-node-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}

When the in prop is set to true, the child component will first receive the class example-enter, then the example-enter-active will be added in the next tick.

Dipen Shah
  • 25,562
  • 1
  • 32
  • 58
  • Thanks for this, after some digging it seems like it's an issue with `fadeEffectVisible` always returning false. That being said, I'm not sure exactly how to change the state to `true`. Any suggestions, given my code above? – Jesse Winton Sep 28 '20 at 15:23
  • @JesseWinton you can use any even handler for example use click or even in constructor you can set default stat to true. – Dipen Shah Sep 28 '20 at 15:28