DEV Community

Cover image for Animate Web Sections with useSection Hook
Hayyan Hami
Hayyan Hami

Posted on • Edited on • Originally published at hayyaun.ir

Animate Web Sections with useSection Hook

Sometimes, you may want to trigger an animation for a specific section based on whether the user has switched to that section. Here’s how you can achieve this:

Usage

By using this hook, you can run animations based on scroll direction while maintaining consistency between transitions. In certain scenarios, you may want to trigger different animations depending on the section you’re navigating from or to or even the direction if going forward or backward. We'll be building this hook in this post.

// SecondSection.tsx
import { Section } from './enums.ts'

export default function SecondSection() {
  const { active } = useSection(
    () => ({
      section: Section.Second,
      enter(back) {
        // fade-in
        if(!back) ...  // when coming from previous (1 -> 2)
        else ...       // when coming from next (3 -> 2)
      },
      leave(back) {
        // fade-out
        if(!back) ...  // when going forward (2 -> 3)
        else ...       // when going backward (2 -> 1)
      },
    }),
    [],
  );

  return ...
}
Enter fullscreen mode Exit fullscreen mode

Configuration

1. Define Sections as an Enum

First, create an enum to represent your sections. For example:

// enums.ts
enum Section {
  First,
  Second,
  Third,
}
Enter fullscreen mode Exit fullscreen mode

2. Global State Management

To manage global state, consider using a library like zustand. Here’s an example of setting up a store:

// store.ts
import { create } from 'zustand'

const useStore = create((set) => ({
  section: Section.First,
  setSection: (section) => set((state) => ({ section })),
}))
Enter fullscreen mode Exit fullscreen mode

3. Watch Section Changes

Create a custom hook called usePrevious that stores the previous value and triggers an effect when the section changes:

// usePrevious.ts
import { useEffect, useRef } from "react";

export default function usePrevious<T extends any[]>(fn: (prev: T) => any, deps: T) {
  const previousDepsRef = useRef<T>(deps);

  useEffect(() => {
    const eject = fn(previousDepsRef.current);
    previousDepsRef.current = deps;
    return eject;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps);
}
Enter fullscreen mode Exit fullscreen mode

4. Create the useSection Hook:

Finally, implement the useSection hook with four events: enter, leave, enterBack, and leaveBack. This hook will help you manage section transitions:

// useSection.ts
import { DependencyList, useMemo, useState } from "react";
import usePrevious from "@/hooks/usePrevious";
import { useStore } from "@/store";
import { Section } from "@/ts/enums";

type Config = {
  section: Section;
  enter?: (from: Section, back: boolean) => Function | void;
  leave?: (to: Section, back: boolean) => Function | void;
};

export default function useSection(
  getConfig: () => Config,
  deps: DependencyList,
) {
  const section = useStore((s) => s.section);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const config = useMemo(getConfig, deps);
  const [target] = useState<Section>(config.section);

  // same as useEffect but with previous values
  usePrevious<[Section, Config | undefined]>(
    ([fromSection]) => {
      if (section === target) {
        const back = target < fromSection;
        return config.enter?.(fromSection, back);
      }
      if (fromSection === target) {
        const back = target > section;
        return config.leave?.(section, back);
      }
    },
    [section, config],
  );

  const active = useMemo(() => section === target, [section, target]);

  return { section, active };
}
Enter fullscreen mode Exit fullscreen mode

Feel free to explore the implementation on my portfolio website. Let me know if you have any questions!

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more