Нашёл решение, через создание специального компонента, который принимает чайлд
index.tsx
// Base
import React from 'react';
import { CSSTransition } from 'react-transition-group';
import useExpandableWrapper from './useExpandableWrapper';
// Assets
import styles from './style.module.scss';
import animation from './animation.module.scss';
interface ExpandableWrapperProps {
isExpanded: boolean;
}
const ExpandableWrapper: React.FC<ExpandableWrapperProps> = ({
children,
isExpanded,
}) => {
const { onEnter, onEntered, onExit, onExiting, state } = useExpandableWrapper();
const { childHeight } = state;
return (
<div style={{ height: childHeight }} className={styles.wrapper}>
<CSSTransition
in={isExpanded}
timeout={600}
classNames={animation}
onEnter={onEnter}
onEntered={onEntered}
onExit={onExit}
onExiting={onExiting}
unmountOnExit
>
{children}
</CSSTransition>
</div>
);
};
export default ExpandableWrapper;
style.module.scss
.wrapper {
overflow: hidden;
transition: height 300ms ease;
height: auto;
}
useExpandableWrapper.ts (Хук вьюхи)
import { useState } from 'react';
const useExpandableWrapper = () => {
const [childHeight, setChildHeight] = useState<string | number>(0);
const onEnter = (element: HTMLElement) => {
const height = element.offsetHeight;
setChildHeight(height);
};
const onEntered = () => {
setChildHeight('auto');
};
const onExit = (element: any) => {
const height = element.offsetHeight;
setChildHeight(height);
};
const onExiting = () => {
const height = 0;
setChildHeight(height);
};
const state = {
childHeight,
};
return {
onEnter,
onEntered,
onExit,
onExiting,
state,
};
};
export default useExpandableWrapper;
animation.style.scss (Файл с анимацией)
.enter {
opacity: 0;
transition: all 600ms cubic-bezier(0.15, 0.84, 0.21, 0.96);
}
.enterActive {
opacity: 1;
}
.exit {
opacity: 1;
transition: all 300ms cubic-bezier(0.15, 0.84, 0.21, 0.96);
}
.exitActive {
opacity: 0;
}