Now that react supports hooks you might add one to this project e.g. like this:
const myButton = ({isVisible}) => {
const {ref, className} = useCssTransitionGroup({in: isVisible, classNames: 'button'});
return <button className={className} ref={ref}>Click me</button>;
}
This would allow people to wrap the library hook with a special behaviour based on their project requirements like this:
const useSlideIn = ({in}) => useCssTransitionGroup({in, classNames: 'slide'});
or
const useSlideIn = ({in}) => useCssTransitionGroup({onEnter: () => /* special slide logic */, in, classNames: 'slide'})
And then reuse such a transition effect multiple times in the project:
const Component1 = () => {
const {ref, className} = useSlideIn({in});
return <div ref={ref} className={className}>...</div>
}
I assume you meant useCssTransition, not useCssTransitionGroup? 馃檪 You can also very easily create a SlideIn component which composes CSSTransition, but I do appreciate the flatter syntax of hooks and the flexibility it provides, although I would rather change the API to return an array instead:
const [transitionRef, transitionClassName] = useCssTransition({ in: isVisible, classNames: 'button' })
That way it will be easier to create multiple transitions because array destructuring makes it easier to name variables differently so they don't clash (which I assume is why useState has the same API).
I'll put a pin in this idea and come back to it later, thanks for the suggestion and feel free to discuss further.
Oh yes you are absolutely right - useCssTransition is way better.
Maybe it would also have a third return value to support the mounted/unmount feature:
const [transitionRef, transitionClassName, inDom] = useCssTransition({ in: isVisible, classNames: 'button' });
return inDom && <div ... >
And yes - the array syntax is probably better here - className is a quite often used variable and maybe you would even like to add two animations at the same time.
Hello,
Please forgive me for this little aside, but still related to using hooks to set a classname after on a component lifecycle event.
I came a few times to look at the features of React Transition Group but I've always found a workaround and avoided adding it to the project dependency. Now that React hooks are stable and I have a project involving animations that require this kind of features, I tried to implement a custom hook useTransition with useState and useEffect, because I forget about React Transition Group before starting doing this...
https://codepen.io/creative-wave/pen/vMRRWd
My hook has serious limitations. The features exposed in your comments are also very nice. But this proof of concept seems ok for my current project and I was just wondering why React Transition Group is using a node reference to force a reflow. It's not easy to debug through setTimeout callbacks, but it seems that they are called in the right order in my tests.
Do you have some insights to give me or links to look at on this topic?
EDIT: comments from this PR was helpfull. I've also been able to see why a reflow might be seen as necessary, but an easy workaround is to make enter overlapping a bit over enter--active, ie. using a timeout with a delay a few ms longer. Anyway, I think that something using node reference like how React Spring is doing it is the most performant solution.
I rewrite class Transition Component with useTransition Hook.
https://codesandbox.io/s/x773r3zq2p
const duration = 300;
const defaultStyle = {
transition: `opacity ${duration}ms ease-in-out`,
opacity: 0,
};
const transitionStyles = {
entering: { opacity: 1 },
entered: { opacity: 1 },
exiting: { opacity: 0 },
exited: { opacity: 0 },
};
function FadeExample({ show, ...other }) {
const [status, unmounted, nodeRef] = useTransition<HTMLDivElement>({ in: show, timeout: duration, unmountOnExit: true });
if (unmounted) return null;
return (
<div
{...other}
ref={nodeRef}
style={{ ...defaultStyle, ...transitionStyles[status] }}
/>
);
}
@chilbi Ah that鈥檚 amazing, was looking for exactly that just now! Would love to see this merged into the library.
@chilbi that's a quite complex solution for people looking for an easy way to animate mounting component, I mean it's working, but is a deep dig code to follow. still big up for your commitment
So, can we expect to see hooks integrated into the library any time soon?
Hopefully soonish 馃槣 I'll start working on improving our test suite, then I'll see what to do from there, I also want to resolve #623, but maybe these will happen simultaneously.
I might be oversimplifying things, but I think this basic hook is enough:
enum TransitionStage {
entering = 'entering',
entered = 'entered',
exiting = 'exiting',
exited = 'exited',
appear = 'appear',
}
export function useInOutTransition(value: boolean, duration: number) {
const [state, setState] = useState(value ? TransitionStage.appear : TransitionStage.exited);
const isInitialRun = useRef(true);
const durationRef = useRef(duration);
durationRef.current = duration; // use latest
useEffect(() => {
if (isInitialRun.current) {
isInitialRun.current = false;
return () => {};
}
setState(value ? TransitionStage.entering : TransitionStage.exiting);
const tmId = setTimeout(() => {
const next = value ? TransitionStage.entered : TransitionStage.exited;
setState(next);
}, durationRef.current);
return () => {
if (tmId) clearTimeout(tmId);
};
}, [value]);
return state;
}
{state !== TransitionStage.exited && <div>...</div>}
Most helpful comment
I rewrite
class Transition ComponentwithuseTransition Hook.https://codesandbox.io/s/x773r3zq2p
Use Example: