[React Router v6] NavLink 스타일이 먹지 않을 때

NavLink는 이동한 페이지와 현재페이지가 같은 페이지면 active 클래스를 갖게 한다. 그래서 메뉴바에 이용했는데 active클래스는 정상적으로 적용되는데 스타일을 먹지 않아서 내가 어디를 잘못했는지 한참 찾아야만 했다....ㅜㅜ 근데 허무하게 스타일부분에 &.active 이렇게 해야 했는데 그냥 .active를 해서 먹지 않았던 것이었다. 하하..
그래도 어디가 문제인지 하나씩 NavLink를 계속 변경해보면서 겪어냈으니 다음에는 시간낭비할 일이 없겠다.

import React from 'react';
import styled, { css } from 'styled-components';
import { NavLink } from 'react-router-dom';

const categories = [
  {
    name: 'all',
    text: '전체보기',
  },
  {
    name: 'business',
    text: '비즈니스',
  },
  {
    name: 'entertainment',
    text: '엔터테이먼트',
  },
  {
    name: 'health',
    text: '건강',
  },
  {
    name: 'science',
    text: '과학',
  },
  {
    name: 'sports',
    text: '스포츠',
  },
  {
    name: 'technology',
    text: '기술',
  },
];

const CategoriesBlock = styled.div`
  display: flex;
  margin: 0 auto;
  width: 768px;
  padding: 1rem;
  @media screen and (max-width: 768px) {
    width: 100%;
    overflow-x: auto;
  }
`;

const Category = styled(NavLink)`
  cursor: pointer;
  font-size: 1.125rem;
  /* white-space: pre; */
  text-decoration: none;
  padding-bottom: 0.25rem;

  &:hover {
    color: #495027;
  }

  & + & {
    margin-left: 1rem;
  }

  &.active { // 👏 이 부분!!!
    font-weight: 600;
    border-bottom: 2px solid blue;
  }
`;

export default function Categories({ category }) {
  // const activeStyle = {
  //   fontWeight: '800',
  //   borderBottom: '2px solid blue',
  // };
  return (
    <CategoriesBlock>
      {categories.map(c => (
        <Category
          key={c.name}
          className={({ isActive }) => (isActive ? 'active' : undefined)}
          to={c.name === 'all' ? '/' : `/${c.name}`}
        >
          {c.text}
        </Category>
      ))}
    </CategoriesBlock>
  );
}

결론
계속 뭔가 안된다면 다른데를 한번쯤 의심해보자..

현재 React Router V5를 적용한 상태의 책을 참고하면서 스스로 깃헙블로그에 정리했던 포스팅과 공식문서를 보면서 중첩된 라우터, URL파라미터, 쿼리스트링을 읽어오게 코드를 짰는데 성공했다. 재밌다.


App.jsx

import React, { useState, useCallback } from 'react';
import NewsPage from './pages/NewsPage';
import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Routes>
      <Route path='/' element={<NewsPage />}>
        <Route path=':category' element={<NewsPage />} />
      </Route>
    </Routes>
  );
}

export default App;

NewsPage.jsx

import React from 'react';
import Categories from '../components/Categories';
import NewsList from '../components/NewsList';

export default function NewsPage() {
  return (
    <>
      <Categories />
      <NewsList />;
    </>
  );
}

Categories.jsx

import React from 'react';
import styled, { css } from 'styled-components';
import { NavLink } from 'react-router-dom';

const categories = [
  {
    name: 'all',
    text: '전체보기',
  },
  {
    name: 'business',
    text: '비즈니스',
  },
  {
    name: 'entertainment',
    text: '엔터테이먼트',
  },
  {
    name: 'health',
    text: '건강',
  },
  {
    name: 'science',
    text: '과학',
  },
  {
    name: 'sports',
    text: '스포츠',
  },
  {
    name: 'technology',
    text: '기술',
  },
];

const CategoriesBlock = styled.div`
  display: flex;
  margin: 0 auto;
  width: 768px;
  padding: 1rem;
  @media screen and (max-width: 768px) {
    width: 100%;
    overflow-x: auto;
  }
`;

const Category = styled(NavLink)`
  cursor: pointer;
  font-size: 1.125rem;
  /* white-space: pre; */
  text-decoration: none;
  padding-bottom: 0.25rem;

  &:hover {
    color: #495027;
  }

  & + & {
    margin-left: 1rem;
  }

  &.active {
    font-weight: 600;
    border-bottom: 2px solid blue;
  }
`;

export default function Categories() {
  return (
    <CategoriesBlock>
      {categories.map(c => (
        <Category
          key={c.name}
          className={({ isActive }) => (isActive ? 'active' : undefined)}
          to={c.name === 'all' ? '/' : `/${c.name}`}
        >
          {c.text}
        </Category>
      ))}
    </CategoriesBlock>
  );
}

NewsList.jsx

import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import axios from 'axios';
import NewsItem from './NewsItem';
import { useParams } from 'react-router-dom';

const NewsListBlock = styled.div`
  box-sizing: border-box;
  width: 768px;
  margin: 0 auto;
  margin-top: 2rem;

  @media screen and (max-width: 768px) {
    width: 100%;
    padding: 0 1rem;
  }
`;

export default function NewsList() {
  const { category } = useParams();

  const [articles, setArticles] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const query = category ? `&category=${category}` : '';
        const response = await axios.get(
          `https://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=29a0160871334cf6861f6fb96d4f86c4`
        );

        setArticles(response.data.articles);
      } catch (e) {
        console.log(e);
      }
      setLoading(false);
    };
    fetchData();
  }, [category]);

  if (loading) {
    return <p>로딩중</p>;
  }

  if (!articles) {
    return null;
  }

  return (
    <NewsListBlock>
      {articles.map(article => (
        <NewsItem key={article.url} article={article} />
      ))}
    </NewsListBlock>
  );
}

좋은 웹페이지 즐겨찾기