리액트 네이티브 expo 도전기 (2)

JoonPark·2023년 12월 4일
0

리액트 네이티브

목록 보기
2/2
post-thumbnail

서론

회사에서 어플에 랜딩 페이지 애니메이션이 있으면 좋겠다는 기능 요구가 발생했다. 그러니까, 웹뷰를 보여주기 전에 잠깐 서비스에 대한 멋드러진 소개가 필요하다는건데....

기능 요구 정리

  • 회사에서 요구한 내용을 다시 정리해보자면 웹뷰 출력 전 소개 이미지와 텍스트를 출력
  • 이 이미지는 '3초간 우측에서 좌측으로 움직'여야 하며, 텍스트는 그렇지 않고 고정
  • 해당 이미지는 제시된 2개 이상의 이미지가 랜덤으로 출력

여러분은 이렇게 코드 짜시면 안됩니다

기능에 대해 들었을때는 'useState와 setTimeout으로 일단 틀 잡기는 쉽겠네?' 라는 생각을 했다

// App.jsx
export default function App() {
  const [showLanding, setShowLanding] = useState(true);
  
  useEffect(() => {
    setTimeout(() => {
      setShowLanding(false);
    }, 3000);
  }, []);
  
  if (showLanding) {
    return <Landing setShowLanding={setShowLanding} />;
  }
  
  return (
    <View style={styles.container}>
      <WebView
        source={{ uri: "서비스" }}
      />
    </View>
  );
}

이 코드는 다음과 같은 문제점이 있다

  • 3초라는 기능 요구에 너무 매몰된 나머지, 말 그대로 3초만 보여줄 것을 가정했다. 만약 랜딩 페이지의 애니메이션이 추후 길어지거나 짧아지면? (물론 매번 부모컴포넌트에서 수정해줄 수 있긴하지만...)
  • 모바일 앱에는 스플래시 이미지라는 게 있다. 앱이 구동준비가 되기까지 보여주는 로딩화면같은건데, 이 로딩 속도가 들쭉날쭉해서 setTimeout으로 보여주는 시간이 일정치 않다.

저는 이렇게 수정했습니다

  • 자식 컴포넌트에서 로직을 진행한 후 부모 컴포넌트에 함수신호를 주어 렌더를 종료하기로 했다.
// App.jsx
export default function App() {
  // useEffect, setTimeout 로직 삭제
}
// Landing.jsx
import { View, Animated, ImageBackground, Text, StyleSheet } from "react-native";
import LandingImg from "넣을 이미지.jpg";

const AnimatedImageBackground =
  Animated.createAnimatedComponent(ImageBackground);

export default function Landing({ setShowLanding }) {
  const moveAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(moveAnim, {
      toValue: 1,
      duration: 3500,
      useNativeDriver: false,
    }).start(() => setShowLanding(false));
  }, []);

  const movingBackground = moveAnim.interpolate({
    inputRange: [0, 1],
    outputRange: ['0%', '-40%']
  });
  
    return (
    <View style={{ flex: 1 }}>
      <AnimatedImageBackground
        source={LandingImg}
        style={{
          width: '120%', 
          height: '120%',
          position: 'absolute',
          left: movingBackground
        }}
        resizeMode="cover"
      />
      <View style={styles.textContainer}>
        <Text style={[styles.textBase, styles.text1]}>텍스트 1</Text>
      </View>
    </View>
  );
}

코드 해설

  • 부모 컴포넌트에서 자식컴포넌트에 대한 렌더링을 결정하는건 똑같지만, 종료 조건은 자식컴포넌트에게로 가져왔다.
  • 마침 Animated.timing이라는 멋진 메소드가 있어 이를 사용해 끝나는대로 즉시 상태를 false, 종료상태로 바꿀 수 있었다.
  • setShowLanding이라는 useState 함수를 프롭스의 형태로 가져왔다.
  • 기본적으로 어떤 이미지든 120%로 확대하고 왼쪽에서 오른쪽으로 40% 이동하므로 정지된 이미지라도 조금 더 세련된 연출이 가능해졌다.

결론

  • 아니나 다를까 샘플 이미지 시연 직후 3초는 애니메이션이 너무 빠르니 5초로 바꿔보는게 어떨까요? 라는 질문에 즉시 수치만 변경해서 0.5초 단위로 계속해서 다시 보여드릴 수 있었다.
  • 만약 이 문제를 수정하지 않았다면 자식컴포넌트에서 애니메이션 속도 조절하고 부모컴포넌트에서 랜딩 페이지 보여줄 시간 조절하고 아주 복잡했을 것이다...
  • 프론트는 유저와 직접적으로 맞닿아 있는 부분을 개발하기 때문에 피드백도 빠르고, 언제나 고객의 입장에서 서비스를 구축할 수 있다는 부분이 만족스럽다.
profile
FE Developer

0개의 댓글