윤스페이스 : 일상을 기록합니다.

 

React를 기반으로 시작한 SAILET 프로젝트를 진행하면서 react-router-dom을 사용했는데, 활성화된 페이지의 아이콘 변경을 설정하는데 24시간 삽질 끝에 성공했다. 간단하게 설정될 줄 알았는데 후,, 생각보다 복잡했다.

 

일단 내가 원했던 기능은, 활성화된 페이지에 따라 하단 바 아이콘 변경을 위해 react-router-dom의 NavLink를 사용하는 것이였다. 

 

react-router-dom의 기본기는 Velopert님의 포스팅을 참고하자.

 

react-router-dom 문서의 <NavLink> 섹션을 번역해보자면,

 

<NavLink>

렌더링 된 요소가 현재 URL과 일치 할 때 스타일 특성을 추가할 수 있는 <Link>의 확장 버전입니다.

 

activeClassName : string

렌더링 된 요소가 현재 URL과 일치할 때 클래스를 부여합니다. 기본적으로 active 클래스를 부여합니다. 기존 className 설정에 추가됩니다. 

<NavLink to="/faq" activeClassName="selected">
  FAQs
</NavLink>

 

activeStyle: object

렌더링 된 요소가 현재 URL과 일치 할 때 스타일을 부여합니다. 

<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: "bold",
    color: "red"
  }}
>
  FAQs
</NavLink>

 

exact: bool

설정이 활성화되면 class, style, to가 정확히 일치하는 경우에만 적용됩니다.

<NavLink exact to="/profile">
  Profile
</NavLink>

 

isActive: func

링크가 활성화되어 있는지 확인하는 함수입니다. 

const oddEvent = (match, location) => {
  if (!match) {
    return false
  }
  const eventID = parseInt(match.params.eventID)
  return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
  to="/events/123"
  isActive={oddEvent}
>Event 123</NavLink>

 

처음에는 isActive를 이용해서, !match에서 true, false 값을 받아오고, 그에 맞는 아이콘을 불러오려 하였으나 계속된 삽질에도 적용되지 않았다. 그리고 결정적으로 좀 이상했던 게 isActive에서 함수를 실행한다는 거다. isActive에서 함수를 실행하지 말고 그냥 바로 isActive 때리면 true나 false 나오면 좋았을 텐데 그런 부분이 아쉬웠다. 

 

 

isActive로 시도한 코드는 아래와 같다.

class Bottom extends React.Component {
  state = {
    iconName : 'initialIconName'
  }

  setIconName = (name) => {
    this.setState(() => ({
      iconName: name
    }))
  }

  oddEvent = (match, location) => {
  if (!match) return false
  console.log(location.pathname.substr(1).split('/')[0])
  this.setState(() => ({
    iconName: location.pathname.substr(1).split('/')[0]
  }))
  }

    render() {
      return (
          <fragment>
            <div className="bottom noright">
              <div className="bottomcontents">
                <div className="bottomicon">
                    <NavLink className="bottomiconinside bottomiconinsideside" src={home} exact to="/" isActive={this.oddEvent}>
                    <img className="iconcenter" src={require(`./home${this.state.iconName == 'home' ? 'sel' : ''}.svg`)}/>
                    </NavLink>
                    <NavLink className="bottomiconinside bottomiconinsideside" exact to="/search" isActive={this.oddEvent}>
                    <img className="iconcenter" src={require(`./search${this.state.iconName == 'search' ? 'sel' : ''}.svg`)}/>
                    </NavLink>
                    <NavLink className="bottomiconinside bottomiconinsideside" to="/add" isActive={this.oddEvent} >
                    <img className="iconcenter" src={require(`./add${this.state.iconName == 'add' ? 'sel' : ''}.svg`)}/>
                    </NavLink>
                    <NavLink className="bottomiconinside bottomiconinsideside" to="/account" isActive={this.oddEvent}>
                    <img className="iconcenter" src={require(`./account${this.state.iconName == 'account' ? 'sel' : ''}.svg`)}/>
                    </NavLink>
                    <NavLink className="bottomiconinside bottomiconinsideside" exact to="/setting" isActive={this.oddEvent}>
                    <img className="iconcenter" src={require(`./setting${this.state.iconName == 'setting' ? 'sel' : ''}.svg`)}/>
                    </NavLink>
                </div>
              </div>
            </div>
              </fragment>
        );
    }

  }

export default Bottom;

stackoverflow에 질문 결과 setState가 포함되어 있는 함수인 oddEvent를 return 내부인 isActive에서 실행시켜 줘서 그렇다고 한다. "You will have to re-think your design." 그래서 처음부터 다시 시도하기로 했다. 

 

react-router 문서를 뒤지기도 하고, 다른 웹사이트는 어떻게 아이콘을 바꿔주나 싶어서 찾아보니, 보통 아이콘을 한 번에 불러오고 css의 background-image를 사용하고 있었다. 인스타그램의 경우 이러한 파일을 불러와서 position과 size를 지정해준다. 트래픽을 최소화시키려고 안간힘을 쓰는 것 같은데 굳이 이렇게까지 할 필요가 있나 싶다.

 

 

background-image를 사용하는 것도 어쨌든 css를 사용하는 것이기에 activeStyle을 사용하면 됐다. 전날 다 못 푼 숙제를 다음날 일어나자마자 10분 만에 해결한 케이스. 다음부터 졸리면 자고 다음날에 다시 해봐야지. 아이콘의 경우 'iconname'이라는 아이콘이 있으면, 액티브된 페이지의 아이콘은 뒤에 sel을 붙여줬다. (ex) home - homesel 

 

최종적인 코드는 아래와 같다.