yamoo9 / likelion-FEQA

질문/답변 — 프론트엔드 스쿨, 멋사
29 stars 9 forks source link

[LAB-14] 스플래시(Splash) 이미지 구현 오류 #233

Closed hamjongseok closed 1 year ago

hamjongseok commented 1 year ago

질문 작성자

함종석

문제 상황

안녕하세요 야무쌤 !! 프로젝트중 스플래시 이미지를 정상적으로 구현하였습니다. 하지만 navigator에서 홈 아이콘을 누르면 Link to = '/' 이므로 홈으로 이동이되는데 이때마다 스플래시 이미지가 계속 나오는 상황이 발생되어 처음접속할때만 나오게끔 구현을하려했으나.. 오류가 발생합니다

스크린샷 2023-03-26 오전 6 32 03

저는 처음 접속을 할때에만 스플래시 이미지를 띄워주고 그다음에는 값을 localStorage로 기억하여 조건처리로 하였습니다 하지만 스플래시이미지가 아닌 setTimeout은 되는데 그냥 렉먹은거처럼 회색 화면만 나오는현상이 계속발생합니다.. 아래사진처럼 회색화면 3초 딜레이 후 홈화면이 나옵니다.

스크린샷 2023-03-26 오전 6 25 32

제가원하는대로 첫 접속 이후에 다시 홈버튼을 눌러도
스플래시이미지도 뜨지않고 스플래시 이미지 대신의 회색화면도 뜨지않지만.. 스플래시 이미지가 안뜨는 이유가 뭘까요... ㅠㅠ

프로젝트 저장소 URL

https://github.com/hamjongseok/MofMof/tree/develop

develop branch 있습니다 !

환경 정보

yamoo9 commented 1 year ago

문제 분석

제가 원하는 대로 첫 접속 이후에 다시 홈버튼을 눌러도 스플래시 이미지도 뜨지 않고 스플래시 이미지 대신의 회색 화면도 뜨지않지만.. 스플래시 이미지가 안뜨는 이유가 뭘까요... ㅠㅠ

먼저 @hamjongseok 님께서 작성한 코드에 주석을 작성 해봅니다. 🤔

function App() {
  // 로딩 상태 값 true
  // 스플래시 이미지가 표시 됨
  const [isLoding, setIsLoading] = useState(true);

  // 마운트 이후, 이펙트 콜백 함수 실행
  useEffect(() => {
    // 스플래시 이미지 표시 여부 값 가져오기
    // - 최초 렌더링 : null
    // - 리-렌더링 : 'true' (문자 값)
    const isSplashShown = localStorage.getItem('isSplashShown');

    // 스플래시 이미지가 표시된 적이 있다면?
    if (isSplashShown) {
      // 로딩 상태 값을 false로 변경 요청 (React가 추후 변경함)
      // 리-렌더링 후, 화면에서 스플래시 이미지 감춤
      setIsLoading(false);
    }
    // 스플래시 이미지가 표시된 적이 없다면?
    else {
      // 로컬 스토리지에 isSplashShown 값을 'true'로 저장
      localStorage.setItem('isSplashShown', true);
      // 3초 뒤에 콜백 함수 실행 됨
      setTimeout(
        () =>
          // 리-렌더링 후, 화면에서 스플래시 이미지 감춤
          setIsLoading(false),
        3000,
      );
    }
  }, []);

  return (...);
}

작성된 React 코드의 실행 흐름을 유추해보면 아래 그림으로 그린 순서대로 실행 되요. 스플래시 이미지가 표시되지 않는 이유는 "React.StrictMode에 의한 2번 렌더링(5 → 6 → 7 흐름)" 때문입니다.

앞서 세운 가설을 증명 해봅시다. 아래 영상을 재생해 확인해보세요. React.StrictMode 컴포넌트 코드를 React.Fragment로 변경하니 기대대로 작동합니다. 다만, 새로고침 할 때마다 스플래시 이미지가 잠깐 보이다 보니 "레코드 판이 튀는 느낌"이 들죠. 🙄

https://user-images.githubusercontent.com/1850554/227746905-41d65146-5091-4e68-9815-758110ccb0aa.mp4

문제 해결

App.js 코드를 다음과 같이 작성해보세요. 😊 @hamjongseok님

function App() {

  // 로딩 상태 초기 값은 false
  const [isLoding, setIsLoading] = useState(false);

  // 마운트 이후, 이펙트 콜백 함수 실행
  useEffect(() => {
    // 스플래시 이미지 표시 여부 값 가져오기 
    // JSON.parse 메서드를 사용해야 JavaScript 값으로 변경 됨
    const isSplashShown = JSON.parse(localStorage.getItem('isSplashShown'));

    // 스플래시 이미지가 표시된 적이 없다면?
    if (!isSplashShown) {
      // 로딩 상태 값을 true로 변경 요청 (React가 추후 변경함)
      // 리-렌더링 후, 화면에 스플래시 이미지 표시 됨
      setIsLoading(true);
      // 3초 뒤에 콜백 함수 실행 됨
      setTimeout(() => {
        // 로컬 스토리지에 isSplashShown 값을 저장
        // JSON.stringify 메서드를 사용해야 문자(string) 값으로 변경 됨
        localStorage.setItem('isSplashShown', JSON.stringify(true));
        // 로딩 상태 값을 false로 변경 요청 (React가 추후 변경함)
        // 리-렌더링 후, 화면에서 스플래시 이미지 감춤
        setIsLoading(false);
      }, 3000);
    }
  }, []);

  return (...);
}

코드가 수정된 이후, 첨부된 영상처럼 첫 접속 시에만 스플래시 이미지가 표시됩니다. 이후 새로고침 해보면 더 이상 스플래시 이미지는 표시되지 않습니다. 🙂

hamjongseok commented 1 year ago

감사합니다 야무쌤 StructMode로 두번 실행 되서 아무것도 보여지지않았다가 실행이 되었던거였군요 ! .. 정말 생각도 못했습니다.

하지만 제가 무엇을 놓친것인지... 되질않네요 ... ㅠㅠ 여전히 회색이 처음에 나오고 스플래시 이미지는 보여지지않고 홈화면으로 넘어갑니다 ㅠㅠ 번거로우시겠지만 한번만더 봐주시면감사하겠습니다 !!

https://github.com/hamjongseok/MofMof/tree/develop

야무쌤이 알려주신것에서 또 궁금한것이 있어서 추가 질문을 남겨봅니다.

  1. const isSplashShown = JSON.parse(localStorage.getItem('isSplashShown'));

    localStorage.setItem('isSplashShown', JSON.stringify(true));

    JSON.parse등을 사용하여 true를 문자열형태로 저장하는것과 제가 했던방법처럼 불리언값인 true로 하는것과 어차피 if 조건문에서는 둘다 똑같은 기능을 할텐데 JSON.parse를 해주신 이유가 무엇인지 궁금합니다

    코드를 동작 해서 비교해보니 어떠한점이 차이가 있는지 잘모르겠어서요 !

  2. 스크린샷 2023-03-27 오전 12 09 31

야무쌤의 코드를 그대로 복붙해서 보는데 의문이 드는 코드가있어서 남겨봅니다. useEffect의 if문은 최초 isSplashShown가 null이나 undefined를 반환하는 최초의 1번 접속할때만 들어가는걸로 제가 이해를하고있는데 위의 캡쳐본 주석처럼 setIsLoading(true); 를 왜 또 해주는걸까요 ?

  1. 기본 값이 true여서 최초의 접속시 스플래시이미지를 보여주고 if 문 안에 들어가서 setIsLoding을 false로 처리한뒤 그다음은 if문을 들어가지 않으니 스플래시이미지를 다시 띄우지 않는다는 그러한 로직인거 같은데 맞을까요 ? 그러면 야무쌤의 코드의 경우 StrictMode로 해도 상관없이 잘돌아가는지 궁금합니다..

  1. 위에서알려주신

스크린샷 2023-03-27 오전 12 20 41

이 실행 흐름이 잘 이해가지 않습니다. 제가 생각하는 흐름은

1번 (true값), 2번 return에서 스플래시이미지 실행 -> 3번 useEffect들어와서 4번 const isSplashShown에 null값이 들어옴 그러므로 6번, 7번을 수행하지않는다. -> else 문으로 들어와서 5번 setItem으로 true값으로 설정해주고 setTimeout 실행 false로 인해 더이상 스플래시이미지를 띄우지 않는다 인데,,

React.strictMode로 인하여 두번 렌더링이 되기때문에 5번 에서 true로 값을 설정해주고 6번 으로 넘어간다는 그 논리적 흐름 을 잘모르겠습니다.. 2번 렌더링하기때문에 5번에서 6번으로 넘어가는것이 어떤 관계가 있는지 궁금하며

그렇다 한들 이미 1번에서 true값, 2번 에서 실행을 하게되는데 왜 보이지 않게되는것인지 궁금합니다. useEffect는 마운트가 되었다는 얘기이고 2번에서 이미 true로 인하여 스플래시이미지를 보여줬어야 할거같은데 왜 안보여지고 회색 화면이 나오는것일까요 ? 이 와 관련된 레퍼런스는 어떤것이 있을까요?

이상입니다 감사합니다 !

yamoo9 commented 1 year ago

@hamjongseok 님 결과는 아래 영상에서 볼 수 있듯 잘 작동됩니다. 최초 접속 시에만 스플래시 이미지가 표시되고, 이후 부터는 표시되지 않죠.

추가 답변 1.

JSON 형태의 포멧 저장은 stringify, parse 메서드를 사용하는 것이 기본입니다. 둘의 차이점을 모르겠다고 말하셨는데, 엄연히 다릅니다.

JSON 메서드를 사용해야 올바른 타입으로 읽기, 쓰기 가능합니다. isSplashShown 로컬 스토리지 값을 가져와 해석한 타입은 boolean 이어야 올바릅니다.

추가 답변 2, 3.

제가 남긴 코드를 잘 보세요. 처음 시작할 때 기본 값이 false입니다.

제가 수정해드린 코드는 StrictMode 에서도 잘 작동합니다. 아래 가이드 파일을 다운로드 받아 확인해보세요.

src.zip

추가 답변 4.

좀 더 면밀하게 실행 흐름을 생각해보세요.

StrictMode는 mountunmountmount를 수행하므로 총 2회 렌더링 합니다. 그러므로 1회차 렌더링 과정에서 4번 null이므로 else 블록 문이 실행되고 로컬 스토리지에 값을 저장합니다. 여기서 중요한 것은 setTimeout 코드가 바로가 아니라, 3초 뒤에 실행된다는 점입니다.

또 하나 중요한 점이 StrictMode에 의해 컴포넌트가 unmount 됩니다. 그리고 다시 mount 되죠. 다시 mount 되기 때문에 useEffect는 종속성 배열 아이템이 없어도 다시 실행됩니다.

이 과정이 2회차 렌더링입니다. 그리고 다시 4번에서 true 값이 출력되고 if 조건문 블록이 실행(6) 되죠. 그러면 스플래시 이미지를 바로 감추도록 상태 업데이트를 리액트에 요청(7)합니다.

그리고 리액트는 다시 렌더링 하죠. 그리고는 스플래시 화면을 감춰버립니다. 그래서 종석님 코드가 새로고침 할 때마다 스플래시 이미지가 잠깐 보이는 것입니다.

이후 3초가 지나면 스플래시 화면은 감춰져 있지만, 리액트에 다시 감춰달라고 요청(8)합니다.

그러면 또 리액트는 컴포넌트를 리-렌더링 합니다. 하지만 useEffect는 다시 실행되지 않습니다. 종속성 배열이 비어 있기 때문입니다.

질문과 연관된 useEffect의 실행 흐름에 대해 분석하여 답변한 글도 참고하세요. 🤔

hamjongseok commented 1 year ago

하나하나 질문에 친절한 답변 감사합니다 ! 좀더 자세히 보면서 이해를 한번해봐야겠네요 ! 감사합니다

splashErr2

하지만 아직도 저는 위의 GIF처럼 야무쌤의 코드를 그대로 복붙해도 src파일 올려주신 거를 코드를 그대로 갖다붙여도 위 처럼 회색 화면 만뜨고 스플래시 이미지는 나오지 않고있습니다........ 다른 조원분이 확인해본결과 잘나온다는데 왜 제 컴퓨터에서만 안나오는건지.. 모르겠습니다

진짜 왜이러는걸까요...? 계속 추가적으로 질문을 드려죄송합니다..

최신화해서 다시 push 하였습니다. https://github.com/hamjongseok/MofMof/tree/develop

yamoo9 commented 1 year ago

@hamjongseok 님 내려 받아 그대로 실행해 본 결과 정상 작동합니다. 😳

아마도 종석님 Chrome 웹 브라우저에서만 제대로 보이지 않는 듯 하네요. 가설 증명을 위해 다음 절차대로 진행해보세요.

  1. Chrome 웹 브라우저 말고, 다른 웹 브라우저에서 http://localhost:3000 주소를 입력하고 확인한다.
    만약 정상적으로 스플래시 이미지가 표시된다면? Chrome 웹 브라우저에 문제가 있을 것입니다.

  2. Chrome 웹 브라우저 개발 도구를 열고, "캐시 비우기 및 강력 새로고침" 하고 다시 시도해봅니다.

    만약 스플래시 이미지가 정상적으로 표시된다면? 캐시를 비우지 않아 발생한 문제일 것입니다.

  3. Chrome 웹 브라우저 시크릿 창(Secret Window)을 띄운 후, http://localhost:3000 주소를 입력해 확인합니다.

    만약 정상적으로 스플래시 이미지가 표시된다면? 설치된 Chrome 확장에 문제가 있을 것입니다.

  4. 만약 Chrome 확장에 문제가 있다고 의심된다면?
    의심되는 확장을 하나 하나 지워가면서 어떤 확장이 문제인지 확인해야 합니다. 😱
hamjongseok commented 1 year ago

하하 1번 3 번 다 되네요.. 2번을 시도해도 정상작동을 하지는않지만 일단 넘어가야겠습니다

너무감사합니다 큰도움이되었습니다!