Web Dev/React.js

[REACT] react-router-dom 및 module.css 사용 중 이슈

hanseongjun 2024. 8. 15. 23:47

개요

react-router-dom을 이용해 nav바를 만들어 routing을 제어하고, activeclassname 속성을 활용하여 nav바에서 선택된 이름을 표시하는 기능을 구현했었다.

<div className={styles['nav-center']}>
    <NavLink to='/' className={styles.navlink} activeclassname={styles.active}><span>Home</span></NavLink>
    <NavLink to='/category' className={styles.navlink} activeclassname={styles.active}><span>Category</span></NavLink>
    <NavLink to='/tags' className={styles.navlink} activeclassname={styles.active}><span>Tags</span></NavLink>
    <NavLink to='/about' className={styles.navlink} activeclassname={styles.active}><span>About</span></NavLink>
    <SearchBar />
</div>

문제상황

그런데 css modules을 이용하면서 문제가 생겼었는데, css modules에선 className 및 일부 요소들만 뒤에 hash를 붙여서 고유하게 되기 때문에 activeclassname으로 지정한 .active 클래스 이름이 적용되는 과정에서 문제가 생겼다.

activeclassname으로 지정한 .active 클래스가 (해당 path일때 클래스가 추가됨) 분명 styles.을 붙여서 넣었는데도 뒤에 해시가 붙지 않고 들어가는 문제가 생긴 것이다.

해결 1

이 문제를 해결하는데엔 다양한 해결 방법이 있다.

  1. :global()을 사용해 선택자를 global화 시킨다.
  2. 따로 .css파일을 만들어 그쪽으로 해당 부분을 옮긴다.
  3. 따로 className에 js를 이용해 현재 path를 기반으로 class를 넣어준다.

여기서 1.과 2.는 해당 className이 전역화된다는 문제가 있어 css Modules를 쓰는 의미가 없어진다고 생각했다.

따라서 3.의 방법을 사용해 현재 path일 시에만 따로 .active클래스를 넣어 주었다.

해결된 코드는 다음과 같다.

// 이렇게 되면 굳이 NavLink를 쓸 필요가 
<div className={styles['nav-center']}>
    <Link to='/' className={`${styles.navlink} ${path === '/' ? styles.active : ''}`} ><span>Home</span></Link>
    <Link to='/category' className={`${styles.navlink} ${path === '/category' ? styles.active : ''}`} ><span>Category</span></Link>
    <Link to='/tags' className={`${styles.navlink} ${path === '/tags' ? styles.active : ''}`} ><span>Tags</span></Link>
    <Link to='/about' className={`${styles.navlink} ${path === '/about' ? styles.active : ''}`} ><span>About</span></Link>
    <SearchBar />
</div>

해결한 사진

쓰다보니 반복되는 부분이 많아 다음과 같이 코드를 간결하게 작성할 수 있었다.

// 따로 navItems 배열 생성
const navItems = [
    {
        name: 'Home',
        path: '/',
    },
    ...

/// nav 부분
<div className={styles['nav-center']}>
    {navItems.map((item, index) => (
        <Link key={`nav-${index}`} to={item.path} className={`${styles.navlink} ${path === item.path ? styles.active : ''}`} ><span>{item.name}</span></Link>
        ))}
    </div>
))}

해결 2

글을 쓰는중에 다른 해결법을 찾았다.
claude가 준 답변중에 힌트가 있었는데 여기서 찾지는 못했었다.

  1. css 선택자중 속성 선택자는 암호화되지 않는다는 점을 이동한다.

수정한 코드

// js
<div className={styles['nav-center']}>
    {navItems.map((item, index) => (
        <NavLink key={`nav-${index}`} to={item.path} className={styles.navlink} activeclassname={styles.active} ><span>{item.name}</span></NavLink>
    ))}
</div>

//css
.navlink[class*="active"]>span {
    color: white;
}

참고 자료

https://stackoverflow.com/questions/57179705/i-was-unable-to-style-the-active-route-in-react-using-react-router

  • 해당 자료에는 (isActive)=>{~~} 이렇게 쓰는 내용과
  • activeClassName={styles.active} 이렇게 해결할 수 있다는 답변이 달려 있지만 실제로 해보면 둘 다 되진 않는다.
  • 심지어 activeClassName으로 쓰면 react에서 activeclassname으로 쓰라고 경고가 뜬다.

https://stackoverflow.com/questions/68783262/react-css-modules-some-css-is-not-applied-for-active-class-set-by-navlink-c

  • 여기 자료를 참고해서 activeclassname속성으로 다시 바꿨다.

참고 - css modules에서 암호화되는 선택자들 - claude.ai에 물어본 결과

  1. CSS Modules에서 암호화되는 선택자들
클래스 이름:
기본적으로 모든 클래스 이름이 암호화됩니다.
예: .className은 .styles_className__1a2b3와 같이 변환될 수 있습니다.

.className {
  color: blue;
}


복합 선택자 내의 클래스 이름:
중첩된 선택자의 각 부분이 개별적으로 암호화됩니다.
예: .nested .element는 .styles_nested__1a2b3 .styles_element__4c5d6로 변환될 수 있습니다.

.nested .element {
  font-size: 16px;
}

composes로 생성된 클래스:
composes 키워드를 사용하여 다른 클래스의 스타일을 상속받은 클래스도 암호화됩니다.
결과적으로 여러 암호화된 클래스 이름이 적용됩니다.

.composeExample {
  composes: className;
  background: yellow;
}


:local 선택자로 감싼 클래스:
:local(.className)과 같이 명시적으로 지역 범위로 선언된 클래스도 암호화됩니다.

:local(.localScoped) {
  border: 1px solid black;
}


미디어 쿼리 내의 클래스 이름:
미디어 쿼리 자체는 암호화되지 않지만, 그 안의 클래스 이름은 암호화됩니다.

@media (max-width: 600px) {
  .responsiveClass {
    font-size: 14px;
  }
}


애니메이션 이름:
@keyframes 규칙에서 사용되는 애니메이션 이름도 암호화될 수 있습니다.


CSS Modules의 확장 기능을 통해 정의된 변수나 믹스인:
일부 CSS Modules 구현에서는 변수나 믹스인도 지역화할 수 있습니다.
  1. CSS Modules에서 암호화(지역화)되지 않는 선택자들:
1. 요소 선택자: main, div, p 등과 같은 HTML 요소 선택자는 암호화되지 않습니다.
main {
  padding: 20px;
}

2. ID 선택자: #idSelector와 같은 ID 선택자도 암호화되지 않습니다.
#idSelector {
  font-size: 16px;
}

3. 속성 선택자: [data-attribute]와 같은 속성 선택자도 암호화되지 않습니다.
[data-attribute] {
  background: yellow;
}

4. 의사 클래스 및 의사 요소: :hover, ::before 등은 암호화되지 않습니다.
a:hover{
    ...
}

5. 전역 선택자: :global()로 래핑된 선택자는 암호화되지 않습니다.
:global(.globalClass) {
  border: 1px solid black;
}

6. 미디어 쿼리: 미디어 쿼리 자체는 암호화되지 않지만, 그 안의 클래스 이름은 암호화됩니다.
@media (...){
    ...
}

7. 키프레임 이름: @keyframes 규칙의 이름은 암호화되지 않습니다.
@keyframes(...){
    ...
}

8. CSS 변수 이름: --variable-name과 같은 CSS 변수 이름은 암호화되지 않습니다.
:root{
    --bg-default: #000000;
    ...
}
LIST