리액트 네이티브에서 슬라이드 버튼을 구현하기 위해 웹의 리액트처럼 translateX
기능이 있는지 궁금하여 찾아보니 Animated
네임스페이스가 리액트 네이티브에서 애니메이션을 담당한다는 것을 발견했다.
아래는 애니메이션에 관련된 함수나 클래스들을 묶어놓은 네임스페이스다.
// node_modules/react-native/Libraries/Animated/Animated.d.ts
export namespace Animated {
export const timing: () => CompositeAnimation;
}
타입스크립트 파일(.ts
)에서 namespace
를 작성할 경우 자바스크립트로 컴파일되면 namespace
는 IIFE
가 된다. 하지만 위 코드는 Typescript Definition file .d.ts
확장자를 가지는 파일에서 작성되므로 컴파일 시 아예 날아가기 때문에 자바스크립트에서는 존재하지 않는 코드가 된다.
const timing: () => CompositeAnimation;
위 문법은 .d.ts
Typescript Definitions 파일에서만 가능한 문법이고 .ts
에서는 const는 초기화없이 선언될 수 없다고 나온다.
const timing = () => CompositeAnimation;
원래 타입스크립트 파일인 .ts
에서는 함수를 위처럼 초기화한다.
위에 나온 timing
함수는 애니메이션이 진행되는 시간(duration
)을 설정할 수 있게 해준다.
그리고 애니메이션에 사용될 스타일 값을 지정하여 값의 변경을 통해 애니메이션을 구현하게 해준다.
useEffect(() => {
Animated.timing(buttonAnim, {
toValue: 100,
duration: 500,
useNativeDriver: true
}, []);
toValue
, duration
, useNativeDriver
3가지 속성이 사용되었다.
export const timing: (
value: AnimatedValue | AnimatedValueXY,
config: TimingAnimationConfig,
) => CompositeAnimation;
위에 timing
함수의 인자 타입을 보면 value
, config
가 있는 것을 볼 수 있는데 timing
함수의 1번째 파라미터인 value
는 useRef
훅스를 써서 초기 애니메이션 값을 지정해주는데 사용한다.
const buttonAnim = useRef(new Animated.Value(0)).current;
// 1번째 인자 buttonAnim이 들어가 있다.
Animated.timing(buttonAnim, config);
value
파라미터는 Animated 네임스페이스 이름 바로 아래에 정의되어 있다.
export namespace Animated {
type AnimatedValue = Value;
type AnimatedValueXY = ValueXY;
}
위 Value
는 클래스이고 Animated
네임스페이스 내부에 등록되어 있다.
export namespace Animated {
class Value extends AnimatedWithChildren {
constructor(value: number, config?: AnimatedConfig | null);
}
}
buttonAnim
은 Animated.Value
클래스의 인스턴스다.
constructor
를 확인해보면 2번째 파라미터로 config?
가 등록되어 있고 그 타입이 AnimatedConfig
인데 이 타입을 보면
interface AnimatedConfig {
readonly useNativeDriver: boolean;
}
위 useNativeDriver
를 사용해도 되고 안해도 되게 설정해놨는데 이 useNativeDriver
는 리액트 네이티브에서 requestAnimationFrame
함수를 사용하여 매 프레임마다 애니메이션 업데이트를 할 때 리액트 네이티브에서 업데이트 한 후 브릿지를 통해 네이티브 코드로 업데이트 값을 전달하는게 아니라 매 프레임마다 업데이트하는 기능을 네이티브 코드 영역에서 수행하게 하여 매 프레임마다 브릿지로 업데이트 값을 전달하는 과정을 제거하여 애니메이션을 최적화하게 해준다.
공식 문서 출처: https://reactnative.dev/blog/2017/02/14/using-native-driver-for-animated
다시 코드로 와서 Value 클래스의 생성자 함수에 인자값으로 useNativeDriver를 넣어주면 아래와 같이 쓸 수 있다.
const buttonAnim = useRef(new Animated.Value(0, { useNativeDriver: true })).current;
공식 문서에서는 new Animated.Value()
생성자 함수를 사용할 때, 첫번째 인자인 value
값만 설정하는 것을 보여주고 있고 두번째 인자인 useNativeDriver
는 설정하지 않고 있다. 프로젝트에서 useNativeDriver
를 추가해보니 buttonAnim
이 스타일에 등록되어 있는 Animated.View
컴포넌트 자체가 기기 화면에서 사라지는 현상을 발견했다.
어떤 이슈가 있는지는 더 확인해보려고 한다.
그리고 useNativeDriver
는 timing
함수의 두번째 인자로 들어가는 config
객체에도 설정해줄 수 있다.
Animated.timing(buttonAnim, {
toValue: 100,
duration: 500,
useNativeDriver: true
});
timing
함수에서는 useNativeDriver
설정을 무조건 해줘야한다.true
값이면 네이티브 코드에서 프레임마다 애니메이션 업데이트를 실시하겠다는 의미로 애니메이션 성능을 최적화한다고 한다.
다음 블로그에서는 buttonAnim.interpolate()
함수와, useNativeDriver
를 Value()
의 두번째 인자에 적용할 경우 발생하는 문제에 대해 살펴봐야겠다.