스플래시 화면과 돌아가기에 대해서

2022. 10. 1. 17:27React/NFT Airdropper

1. 스플래시를 한 번만 나오게 할 순 없을까? 란 생각


1~100까지 차는 스플래시. 서버를 안쓰기 때문에 전혀 가져오는게 없지만 일단 게임같아서 넣음.

 

문득 문서를 만들다가 이런 생각이 들었다.

(이 내용은 어쩌면 개발보다는 약간 기획에 더 가까울 지도 모르겠다.)

나는 메인 화면인 "/" 경로에서 스플래시를 무조건 한 번 돌리고,

그 다음에 안에 문서를 네비게이션을 클릭해서 들어가게 설계했다.

 

그리고 이 서비스의 가장 main contents인 메타마스크와 nft 민팅에 관한 정보를 담은 아티클을 볼 수 있다.

누군가 이걸 보고 세상 비효율적인 구조라고 피드백을 할 수 있겠지만, 애초에 그게 여기의 그라운드 룰이니..

 

아무튼 웬만한 건 다 참을 수 있겠는데 이건 못참겠다.

 

url창이 캡쳐가 안되서 뭔가 싶지만, [뒤로 가기]를 눌렀을 때 "또" 스플래시를 기다려야 한다.

 

사실 저 스플래시는 사이트에 처음들어올 때,

"어떤 콘텐츠가 있을지에 대해 기대감을 주는 장치"이다. 그렇기 때문에 이미 메인 콘텐츠나 메인 화면의 버튼을 통해 다른 곳으로 간 유저가 다시 메인으로 돌아가고 싶을 때 또 저 스플래시를 보는게 문제다.

 

먼저 다른 사이트들을 조사해보자.

 

2. 스플래시 로딩의 대명사 644.kr

여긴 아래 콘텐츠와 스플래시가 같은 url이다.

 

심플하게 기획이 잘되었다. (역시 단순할 수록 문제가 적다.)

스플래시를 다시 봐야하는가? 라는 문제를 모든 콘텐츠를 같은 url에 넣음으로써 해결했다.

(그리고 책속으로 들어가는 것 같은 애니메이션이 굉장히 멋있다.)

 

이걸 보니 더욱 명확해졌다. 스플래시를 어떻게든 해결해야한다.

 

해결 1?. React-Router-Dom의 replace를 true로..?

//...

const moveToDocs = useCallback(() => {
    navigator("/docs", { replace: true });
}, [navigator]);

//..

<NavLink to={"/docs"} replace>Docs</NavLink>

 

일단 이렇게 하면 열받는 스플래시 n 번 보기 문제는 해결된다.

다시 home화면으로 가려면 사용자가 직접 url을 쳐서 들어오거나 링크를 타고 들어와야만 메인 화면을 볼 수 있다.

 

다만, 이건 정말 임시방편이다.

난 누군가가 다시 우리 메인으로 들어와서 애니메이션과 인터렉션을 즐겼으면 좋겠다.

 

그래서 기각!

 

해결 2?. 쿠키를 써볼까?

 

쿠키를 쓸까 하다가, 어차피 리프레시 되거나 새로 타고 오면 스플래시는 무조건 보여줘야한다.

그러면 expire date를 어떻게 설정해줘야하나 싶다는 생각이 든다.

만약 내가 한 탭에 우리 사이트를 켜놓고, 그 다음 탭을 켜서 또 접속했을 때 쿠키로 넣어놓으면 스플래시가 안보여야 하는데, 이게 맞나 싶다는 거다.

 

그래서 기각!

 

해결 3. App.tsx의 최상단에서 state 관리를 해주자!

 

약간은 비효율적인 방법일 수는 있겠지만, 지금 내 수준에선 이렇게 밖에 결론이 안나온다.

라우팅을 관리해주는 최상단 App.tsx에서 state를 하나 넣어주는 방법이다.

 

App.tsx

/** @jsxImportSource @emotion/react */
import React, {useCallback, useState} from 'react';
import './App.css';
import { BrowserRouter, Routes, Route } from "react-router-dom";
import WallPaper from "./layout/Wallpaper/WallPaper";

function App() {
  const [firstSplash, isFirstSplash] = useState(true);
  const skipSplash = useCallback(() => {
    isFirstSplash(false);
  }, [isFirstSplash]);

  return (
    <BrowserRouter>
      <Routes>
        <Route path={"/"} element={<WallPaper isFirstVisited={firstSplash} callback={skipSplash} />}>
          <Route path={"/docs"} element={<WallPaper />} />
          <Route path={"/docs/:language"} element={<WallPaper />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;

 

패스의 가장 위에서 state를 관리해주다가, 처음 스플래시가 끝나면 false로 콜백을 해준다.

이렇게 해두고, firstSplash가 false로 넘어갔을 땐 splash 컴포넌트를 보이지 않게 설정해주면 끝!

 

첫 스플래시 끝나고 false return 해주는 콜백

useEffect(() => {
      if (splashLoadingProgress > 1 && isFirstVisited && callback) callback();
    }, [splashLoadingProgress]);

 

splash component 감싸주기

return (
      <div style={{ position: "absolute" }}>
        {isFirstVisited &&
            <Splash
              className={`${splashLoadingProgress === 1 && "zoomAnimation"}`}
              callbackProgress={progress => onChangeLoading(progress)}
              callbackImgWidth={width => onSetImgWidth(width)} />
        }

Tip) splash의 진행율과 관련된 여담

이걸 다룰까 말까 고민하다가 여담으로 쓰기로 했다.

스플래시 컴포넌트의 진행율을 0부터 1까지 받으면서 1이 되었을 때 class를 추가해주면서 애니메이션을 넣었었다.

 

그래서 최초에 splashLoadingProgress를 1로 초기화해야 했다.

(이래야 splash가 진행되지 않아도 화면전환 애니메이션이 나오니..)

 

여기에서 파생되는 사소한 문제가, callback의 호출 조건이다.

(가정: 첫 스플래시의 진행도가 100%가 되었을 때 callback이 실행되어야 한다.)

 

splashLoadingProgress가 1이상일 때,
isFirstSplash가 true일때,
callback이 null이 아닐때,

 

이 조건에서 callback을 하게 만들면, 최초 초기화 조건(splashLoadingProgress = 1) 때문에 그냥 스플래시가 진행되기도 전에 callback이 되어서 새로 컴포넌트가 그려진다. (결과적으론 스플래시가 실행안된다는 뜻)

 

내가 생각한 방법은 그냥 핸들러에서 처리해주는 방법이다.

 

const onChangeLoading = useCallback((progress: number) => {
      setSplashLoadingProgress(progress === 1 ? 2 : progress);
    }, [setSplashLoadingProgress]);

 

이 핸들러는 progress에서 넘어온 값으로 splashLoadingProgress를 바꿔주기 때문에,

무조건 처음에 0부터 들어와서 1까지 진행된다.

 

그렇기 때문에 1이 왔을 때는 2로 바꿔주면 된다.

 

그리고 콜백 조건을 splashLoadingProgress가 1 초과일때 로 바꿔주자.

그러면 가정했던 최초 스플래시가 100% 되었을 때 콜백이 실행되면서 의도한 결과를 확인할 수 있다!