[에러 일지] 서로 마진 값이 다른 페이지로 이동 시 화면이 깜빡이는 현상

uxolrv·2023년 2월 5일
0
post-thumbnail

❗️ 문제 : 서로 마진 값이 다른 페이지로 이동 시 화면이 깜빡이는 현상

const hiddenPath = ['/login', '/signup'];

function Layout() {
  const { pathname } = useLocation();
  const [isHiddenPath, setIsHiddenPath] = useState(
    hiddenPath.includes(pathname),
  );

  useEffect(() => {
    setIsHiddenPath(hiddenPath.includes(pathname));
  }, [pathname]);


  return (
    ...
    <MainContainer isHiddenPath={isHiddenPath}>
    ...
  )
}

모든 페이지에서 공통적으로 사용하는 Layout 컴포넌트의 코드다.

footer, Nav, margin 값이 없어야 하는 path를 hiddenPath라는 배열에 담아 두었다.
그리고 현재 위치한 pathnamehiddenPath 배열에 포함되었는 지를 확인하는 isHiddenPath 상태에 따라 동적으로 스타일링하여 margin 값을 변경하였다.


이렇게 코드를 작성하고나니, 메인 페이지에서 로그인 페이지로 이동할 때 묘하게 눈이 아픈 것 같고... 뭔가 화면이 깜빡이는 것 같았다.

너무 찰나여서 동영상으로 녹화해서 천천히 돌려보니
margin이 들어가 있는 메인페이지에서 margin이 없는 로그인 페이지로 이동할 때
이전의 margin 값이 아주 잠~시!! 남아 있다가 margin이 사라지는 것을 확인하였다.








💡 원인

원인은 useEffect 였다!

useEffect는 브라우저가 업데이트된 화면을 먼저 렌더링한 후 즉, 레이아웃 작업과 리페인트 작업이 끝난 후에 비동기적으로 실행된다.

페이지 이동으로 인해 새로운 DOM을 생성하여 화면에 렌더링하고 나서야, useEffect에 전달한 상태 변경 함수가 실행되면서 isHiddenPath 상태가 바뀌고, 그에 따라 margin 값이 바뀌기 때문에 잠시 예전의 margin이 남아있는 것이었다!








✨ 해결

If your Effect wasn’t caused by an interaction (like a click), React will let the browser paint the updated screen first before running your Effect. If your Effect is doing something visual (for example, positioning a tooltip), and the delay is noticeable (for example, it flickers), replace useEffect with useLayoutEffect.

리액트 공식문서에 따르면 리액트는 effect를 실행하기 전에 업데이트된 화면을 먼저 페인트하게 되는데, 이때 깜빡임과 같은 지연이 눈에 띄는 경우에는 useEffectuseLayoutEffect로 대체하라고 한다.


🔎 useLayoutEffect

useLayoutEffect는 브라우저가 화면을 리페인트하기 전에 동기적으로 실행되는 useEffect다.

useLayoutEffect를 사용하면

DOM 생성 → `useLayoutEffect` 실행 → 상태 변경에 따라 margin 값 변경 → 리페인트

순으로 진행되기 때문에 margin 값 변경으로 인한 깜빡임이 화면에 나타나지 않게 된다!


const hiddenPath = ['/login', '/signup'];

function Layout() {
  const { pathname } = useLocation();
  const [isHiddenPath, setIsHiddenPath] = useState(
    hiddenPath.includes(pathname),
  );

  useLayoutEffect(() => {
    setIsHiddenPath(hiddenPath.includes(pathname));
  }, [pathname]);


  return (
    ...
    <MainContainer isHiddenPath={isHiddenPath}>
    ...
  )
}

이렇게 보니 useLayoutEffectuseEffect보다 훨씬 좋아보이지만, useLayoutEffect는 성능 저하를 일으킬 수 있기 때문에 가능하면 useEffect를 사용해야 한다고 한다~


예전 같으면 페이지 이동할 때 깜빡이는 줄도 몰랐을 것 같은데
확실히 리팩터링을 하다보니 조금 더 세세하게 사이트를 뜯어보게 되는 것 같다!!

완~~전 미세한 차이지만 요런 미세한 차이들이 모여서 좋은 UI/UX를 만드는 것이 아닌가 싶다~ 🥳








참고
리액트 공식 문서 - useEffect
리액트 공식 문서 - useLayoutEffect

profile
안녕하세연🙋 프론트엔드 개발자입니다

0개의 댓글