티스토리 뷰
대회 프로젝트를 진행하는데, 프론트엔드를 할 사람이 없었다.
이번 프로젝트는 한명이 빠지는 바람에 할 사람이 없다. 심지어 JS 자체를 모르는 분도 있다.
게다가 제 6회 KDT 해커톤 본선까지 진출해버리면서 구현 작업을 더 디테일하게 해야했다.
따라서 필자가 AI 백엔드 기본 구현, 작업 검수에 이어서 프론트엔드까지 전부 구현하고 맡게 되었다. 그러면서 1년 전 기억을 되살려내면서 꾸역꾸역 만들어낸 React 코드이다.
그 중에서도 오늘은 새롭게 알게 된 페이지 전환 애니메이션에 대해서 알아보려고 한다.
일단 간단하게 설명하자면 React-trainsition-group이라는 걸 쓴다.
개인적으로 framer는 뚝뚝 끊기는 느낌이 있어서 이게 더 낫다고 판단하여 쓰게 되었다.
코드는 아래와 같다.
import React from 'react';
import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';
import { TransitionGroup, Transition } from 'react-transition-group';
import ChatPage from './pages/ChatPage';
import HomePage from './pages/HomePage';
import Header from './components/common/Header';
const TIMEOUT = 300;
const getTransitionStyles = (status) => ({
entering: {
position: 'absolute',
opacity: 0,
transform: 'translateX(50px)',
backgroundColor: '#DFD9CE',
},
entered: {
transition: `opacity ${TIMEOUT}ms ease-in-out, transform ${TIMEOUT}ms ease-in-out`,
opacity: 1,
transform: 'translateX(0)',
backgroundColor: '#DFD9CE',
},
exiting: {
transition: `opacity ${TIMEOUT}ms ease-in-out, transform ${TIMEOUT}ms ease-in-out`,
opacity: 0,
transform: 'translateX(-50px)',
backgroundColor: '#DFD9CE',
},
exited: {
opacity: 0,
transform: 'translateX(50px)',
backgroundColor: '#DFD9CE',
},
}[status]);
function AnimatedRoutes() {
const location = useLocation();
return (
<div style={{ position: 'relative', width: '100%', height: '100%', backgroundColor: '#DFD9CE' }}>
<TransitionGroup className="relative w-full h-full">
<Transition key={location.pathname} timeout={TIMEOUT}>
{(status) => (
<div
style={{
...getTransitionStyles(status),
}}
className="w-full h-full absolute top-0 left-0"
>
<Routes location={location}>
<Route path="/" element={<HomePage />} />
<Route path="/chat" element={<ChatPage />} />
</Routes>
</div>
)}
</Transition>
</TransitionGroup>
</div>
);
}
function App() {
return (
<Router>
<div style={{
position: 'relative',
overflow: 'hidden',
width: '100%',
height: '100vh',
backgroundColor: '#DFD9CE' // 최상위 컨테이너에도 배경색 지정
}}>
<Header />
<AnimatedRoutes />
</div>
</Router>
);
}
export default App;
Header는 App.js에 고정하고,
나머지 page 코드나 이런 건 컴포넌트화해서 SOLID 패턴을 중요시했다.
사실 위의 코드도 보여주기식일 뿐, AnimatedRoutes로 컴포넌트화해서 쓸 생각이다.
확실히 쌩 Html로 작동할 때는 어느 코드가 어느 부분에 있는지, JS가 어디에 있는지 헷갈리는데, 리액트는 요소 관리가 편해서 좋다.
다만 이제 Vue보다 상태관리가 조금 더 어렵다는 게 흠이긴 하다.
그래도 동적으로 만들어진 프레임은 확실히 마음에 든다.
아래는 디자인이 없을 때의 시연영상인데, 비교해보면 위가 그래도 더 낫다는 평가를 들었으니 말이다.
혼자서 하려니 작업량이 진짜 많긴 하지만, 꼭 본선에서 다 갈아서 대상 타면 안 억울할거 같다.
그래도 열심히 해야지.
만든 코드는 https://github.com/bellkjtt/budrami-react-django 에서 볼 수 있다.