@react-three/drei
Version:
useful add-ons for react-three-fiber
53 lines (50 loc) • 1.6 kB
JavaScript
import * as React from 'react';
import { Object3D, AnimationMixer } from 'three';
import { useFrame } from '@react-three/fiber';
function useAnimations(clips, root) {
const ref = React.useRef(null);
const [actualRef] = React.useState(() => root ? root instanceof Object3D ? {
current: root
} : root : ref);
const [mixer] = React.useState(() => new AnimationMixer(undefined));
React.useLayoutEffect(() => {
if (root) actualRef.current = root instanceof Object3D ? root : root.current;
mixer._root = actualRef.current;
});
const lazyActions = React.useRef({});
const api = React.useMemo(() => {
const actions = {};
clips.forEach(clip => Object.defineProperty(actions, clip.name, {
enumerable: true,
get() {
if (actualRef.current) {
return lazyActions.current[clip.name] || (lazyActions.current[clip.name] = mixer.clipAction(clip, actualRef.current));
}
},
configurable: true
}));
return {
ref: actualRef,
clips,
actions,
names: clips.map(c => c.name),
mixer
};
}, [clips]);
useFrame((state, delta) => mixer.update(delta));
React.useEffect(() => {
const currentRoot = actualRef.current;
return () => {
// Clean up only when clips change, wipe out lazy actions and uncache clips
lazyActions.current = {};
mixer.stopAllAction();
Object.values(api.actions).forEach(action => {
if (currentRoot) {
mixer.uncacheAction(action, currentRoot);
}
});
};
}, [clips]);
return api;
}
export { useAnimations };