Custom AutoAnimate animation does not work with React

293 Views Asked by At

I'm trying to add the plugin found here in a part of my code. I had to rewrite it because I'm using React, but for some reason it still doesn't work. Can you help me solve the problem?

Custom Hook:

import { useRef, useLayoutEffect } from 'react';
import autoAnimate, { getTransitionSizes } from '@formkit/auto-animate';

interface UseAutoAnimateOptions {
  parentElement: HTMLElement;
}

const useBouncyAutoAnimate = ({ parentElement }: UseAutoAnimateOptions) => {
  const ref = useRef(null);

  useLayoutEffect(() => {
    if (ref.current) {
      autoAnimate(parentElement, (el, action, oldCoords: any, newCoords: any) => {
        let keyframes;
        // ... (rest of the code remains the same)
        if (action === 'add') {
            keyframes = [
              { transform: 'scale(0)', opacity: 0 },
              { transform: 'scale(1.15)', opacity: 1, offset: 0.75 },
              { transform: 'scale(1)', opacity: 1 },
            ];
          }
          if (action === 'remove') {
            keyframes = [
              { transform: 'scale(1)', opacity: 1 },
              { transform: 'scale(1.15)', opacity: 1, offset: 0.33 },
              { transform: 'scale(0.75)', opacity: 0.1, offset: 0.5 },
              { transform: 'scale(0.5)', opacity: 0 },
            ];
          }
          if (action === 'remain') {
            const deltaX = oldCoords.left - newCoords.left;
            const deltaY = oldCoords.top - newCoords.top;
            const [widthFrom, widthTo, heightFrom, heightTo] = getTransitionSizes(
              el,
              oldCoords,
              newCoords
            );
  
            let start: any = { transform: `translate(${deltaX}px, ${deltaY}px)` };
            let mid: any = {
              transform: `translate(${deltaX * -0.15}px, ${deltaY * -0.15}px)`,
              offset: 0.75,
            };
            let end: any = { transform: `translate(0, 0)` };
  
            if (widthFrom !== widthTo) {
              start.width = `${widthFrom}px`;
              mid.width = `${widthFrom >= widthTo ? widthTo / 1.05 : widthTo * 1.05}px`;
              end.width = `${widthTo}px`;
            }
            if (heightFrom !== heightTo) {
              start.height = `${heightFrom}px`;
              mid.height = `${heightFrom >= heightTo ? heightTo / 1.05 : heightTo * 1.05}px`;
              end.height = `${heightTo}px`;
            }
            keyframes = [start, mid, end];
          }
  
          return new KeyframeEffect(el, keyframes as any, {
            duration: 600,
            easing: 'ease-out',
          });
      });
    }
  }, [ref]);

  return ref;
};

export default useBouncyAutoAnimate;

Usage:

import React, { useRef, useState } from 'react'
import Word from './Word';
import { useAutoAnimate } from '@formkit/auto-animate/react'
import useBouncyAutoAnimate from './bouncy';

interface Word {
    id: number,
    visible: boolean,
    word: string
}

interface MultiListProps {
    words: Word[],
    actives: Word[],
    setWords: React.Dispatch<React.SetStateAction<Word[]>>,
    setActives: React.Dispatch<React.SetStateAction<Word[]>>
}

function MultiList({ words, setWords, actives, setActives }: MultiListProps) {

    const parentRef = useRef<HTMLElement | null>(null);
    const animateRef = useBouncyAutoAnimate({ parentElement: parentRef.current! });

    const [ready, setReady] = useState(false);

    return (
        <div ref={parentRef as any}>
            {
                actives.map(word => (
                    <button onClick={() => {
                        const has = actives.find(w => w.word === word.word);
                        if (!has) return;
                        setActives(x => x.filter(w => w.id !== word.id))
                        const newWords = words.map(el => {
                            if (el.id === word.id)
                            el.visible = true;

                            return el;
                        })

                        setWords(newWords)
                    }} ref={ word.id === (actives.at(-1)?.id || NaN) ? animateRef as any : undefined}>
                        <Word word={word} />
                    </button>
                ))
            }
        </div>
    )
}

export default MultiList

Addition Element:

import React, { useState } from 'react'
import Word from './Word';
import classnames from 'classnames';


interface Word {
    id: number,
    visible: boolean,
    word: string
}

interface SelectListProps {
    words: Word[],
    actives: Word[],
    setWords: React.Dispatch<React.SetStateAction<Word[]>>,
    setActives: React.Dispatch<React.SetStateAction<Word[]>>
}

function SelectList({ words, setWords, actives, setActives }: SelectListProps) {

    const [ready, setReady] = useState(false);

    return (
        <div>
            {
                words.map(word => (
                    <button onClick={() => {
                        const has = actives.find(w => w.word === word.word);
                        if (has) return;
                        setActives(x => ([
                            ...x,
                            word
                        ]))

                        const newWords = words.map(el => {
                            if (el.id === word.id)
                            el.visible = false;

                            return el;
                        })

                        setWords(newWords)
                    }} className={classnames('transition-opacity', {
                        'opacity-50': !word.visible
                    })}>
                        <Word word={word} />
                    </button>
                ))
            }
        </div>
    )
}

export default SelectList

Normally, when we click on it, the new element should be added in a 'bouncy' way, but now it comes flat without any animation.

1

There are 1 best solutions below

0
On

I think your error is in the import of the package in your custom hook.

Try changing this:

import autoAnimate, { getTransitionSizes } from '@formkit/auto-animate';

For this:

import autoAnimate, { getTransitionSizes } from '@formkit/auto-animate/react';