내비게이션 상태 관리

YiJaeE·2020년 12월 21일
0
post-thumbnail

이 이미지는 인스타그램 내비게이션이다. 이 내비게이션의 특징적인 점이 몇 가지 있는데,

  1. 클릭하면 페이지가 이동되거나 모달이 뜬다.
  2. 모달이 뜨는 경우 페이지가 이동하지 않기 때문에 마지막으로 이동한 페이지가 활성화 된 상태이다.
  3. 모달을 끌 경우 페이지 변동 없이 마지막으로 이동한 페이지가 활성화 된다.
  4. 모달을 직접 끄지 않고 다른 메뉴를 클릭해서 끄는 형태가 되어도 클릭한 페이지로 이동하지 않고 마지막으로 이동했던 페이지가 활성화 된다.

내비게이션 상태를 한꺼번에 관리하기

처음에는 다섯 개 메뉴의 상태를 한 번에 조작할 수 있을 줄 알고 한꺼번에 상태를 저장했었다.

const navState = {
    home: true,
    direct: false,
    findpeople: false,
    heart: false,
    profile: false,
  };

처음 렌더링 되는 화면에서 늘 home 아이콘이 활성화되어 있었기 때문에 상태를 true로 설정했다. 위 이미지에서처럼 home, direct, findpeople은 라우터를 이용해 페이지가 이동되도록 했고, heart, profile은 모달이 뜨는 동작을 했다.

상태 초기화를 어떻게 할 것인가

이렇게 구현했을 때 발생했던 문제가 라우팅으로 인해 페이지가 새로 렌더링이 될 때마다 home 아이콘이 활성화 되었다가 한 번 더 이동할 메뉴를 클릭해야만 해당 메뉴의 아이콘이 활성화 되는 것이었다. 처음에는 리액트의 렌더링 문제인 줄 알고 구글링을 엄청나게 했었는데 라우팅을 하면 상태가 초기화되면서 true 상태인 home 아이콘이 활성화 되어버리는 문제였다.

라우팅을 하면 새로운 페이지가 렌더링 되는 것이기 때문에 기존의 상태(home: true)를 가지고 있으면 안 된다는 결론이 나왔다. 모든 상태는 false로 정의되어야 했다.

const navState = {
    home: false,
    direct: false,
    findpeople: false,
    heart: false,
    profile: false,
  };

이전 상태를 불러오기

인스타그램 메뉴의 가장 큰 특징은 모달이 보였다가 사라지는 시점에 있다. 모달은 페이지를 이동시키지 않기 때문에 마지막으로 렌더링 된 화면이 그대로 노출되고 있어야 했고, 모달이 사라지면 마지막으로 렌더링 된 화면에 해당하는 메뉴가 활성화 되어야 했다.

상술한 것처럼 상태를 한꺼번에 관리했을 때의 문제는 여기서 드러났다. 클릭과 동시에 아이콘의 활성화 상태는 변경되어야 했는데, 상태를 한꺼번에 관리하게 되면 모달이 나타났다가 사라진 후에 마지막으로 렌더링 된 화면의 메뉴를 활성화 할 수가 없는 것이었다.

사용자가 모달에 접근할 수 있는 루트는 한 가지가 아니었기 때문에 발생하는 문제였다. 모달에 접근하기 전 마지막으로 렌더링 된 화면은 사용자의 임의에 의해 정해졌기 때문에 어떤 메뉴가 마지막으로 활성화 되었는지를 감지해서 능동적으로 반응할 수 있는 방법이 필요했다.

내비게이션 상태 분리하기

우선 떠올릴 수 있는 방법 중 하나는 내비게이션 상태를 분리하는 것이었다. 라우팅으로 페이지가 새롭게 랜더링 되는 메뉴를 묶고, 모달이 나타나는 메뉴를 묶는 것이었다. 이렇게 하면 모달이 나타날 때 상태를 아예 변경하는 것이 아니라 기존에 렌더링 된 페이지의 메뉴 활성화 상태는 그대로 둔 채로 컴포넌트를 활용해 마치 상태가 변경된 것처럼 보이게 할 수 있다.

const navRouteState = {
    home: false,
    direct: false,
    findpeople: false,
  };

const navModalState = {
    heart: false,
    profile: false,
  };

상태를 둘로 나누어 관리하면서 컴포넌트를 라우팅 되는 메뉴가 동작할 때 사용하는 것과 모달이 활성화 되었을 때 사용하는 것 두 개를 만든다. 각 컴포넌트에서 관리하는 상태는 navRouteStatenavModalState 하나면 된다. 사용자가 어떤 아이콘을 클릭하면 조건에 따라 해당되는 컴포넌트만 보여주면 되기 때문이다.

이제 라우팅 되는 페이지를 어떻게 읽어올 것인지에 대한 문제가 남았다.

react-redux 사용하기

상태를 모두 false로 초기화 했을 때 페이지의 상태 혹은 모달의 상태에 따라 아이콘의 활성화 상태가 변경되도록 하려면 외부에서 상태에 대한 단서를 받아서 렌더링 해야 한다고 생각했다.

처음에는 history를 사용하려고 했는데 인스타그램 내비게이션의 경우 모달이 떴을 때 라우팅의 영향을 받지 않고 마지막으로 렌더링 된 화면이 그대로 보이고 있었기 때문에 history를 적용하기에는 어렵겠다는 판단이 들었다.

그래서 외부에서 전달해준 정보를 받아 상태를 변경하기에 유용한 방법으로 react-redux(이하 redux)를 활용하기로 했다. redux를 통해 page에 대한 정보를 전달받아 해당 정보대로 아이콘의 활성화 상태를 조절할 수 있기 때문이다.

페이지가 변경될 때마다 해당 페이지에서 currentPage()를 통해 page 정보를 문자열로 넘겨주는 reducer를 만들었다. 이 reducer는 currentPage()가 동작할 때마다 문자열을 전달하게 된다.

예를 들면 아래와 같은 방식으로 동작한다. HomeContainer가 렌더되면 currentPage()는 'feed'라는 문자열을 전달하게 되고, 실제 아이콘의 렌더를 담당하는 컴포넌트에서 이 문자열을 받아 조건에 따라 해당되는 아이콘의 활성화 상태를 변경하는 것이다.

이렇게 구현하면 현재 어떤 페이지가 렌더 되었는지에 따라 그에 맞는 아이콘의 상태를 변경해줄 수 있게 된다.

상태를 효율적으로 관리하는 법

상태를 항상 외부에서 관리하는 것이 '반드시' 좋은 방법은 아니라고 생각한다. 특정 컴포넌트에서만 사용하고, true/false 상태만을 변경하는 경우라면 굳이 외부로 가지고 나갈 필요는 없기 때문이다. 하지만 능동적으로 현재 렌더된 상태를 가져와야 할 때는 상태를 내부에 두고 조작하기가 오히려 더 까다롭게 느껴졌다. 이럴 때 redux를 활용하면 쉽게 문제를 해결할 수 있다고 느꼈다.

또한 같은 옵션을 가진 상태를 한꺼번에 관리하는 것이 나을 때도 있지만, 동작에 따라 상태와 컴포넌트를 분리하고 조건에 맞는 컴포넌트와 상태가 선택적으로 렌더되도록 하는 방법이 더 나을 때도 있었다.

상태를 관리하는 방법에도 '반드시'라는 건 없기 때문에 어떤 방식이 더 효율적인지 여러 가지 상황을 많이 대입해보는 것이 좋을 것 같다.

profile
개발을 개발개발 🐾

0개의 댓글