MMZ 일지 6. react NavLink 컴포넌트

0
post-thumbnail

혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다

오늘 한 일

  • Header 컴포넌트 리펙토링 & CSS 적용
    : Link 컴포넌트를 사용했다가 NavLink 컴포넌트 적용으로 수정했다.
  • Footer 컴포넌트 CSS 적용

오늘 총평

주말되면 눈이 너무 아프고 부셔서 찡그리면서 작업을 하게 된다. 아침에 핸드폰 좀 보다가 작업해서 그런가.. 안구 건조증은 항상 있어왔는데 눈이 부셔서 아픈건 정말 차원이 다른 불편함이다. 모니터 밝기도 밝게 하는편이 아닌데도 눈이 부셔서 힘들다.
며칠전 v6 기능 보다가 NavLink의 존재를 알게되서 header부분엔 Link보다 활성화 상태를 보여줄 수 있는 NavLink가 더 적절할 것 같았다.(컴포넌트화한 Link를 상속받아서 사용하려고 했지만 styled-components가 적용되어 상속이 어려워서 다시 작업을 하긴 했었다. 이참에 바꾸려고했던 것) 그런데 공식문서 때문에 애먹었다. 기술 블로그에서 먼저 보고 링크된 공식문서를 봤던게 문제였다. 적용해도 activeClassName이라는 속성이 없다고 떠서 타입스크립트 문제인줄 알았으나 차후에 알게된 사실이 v5 공식문서였던 것... 이제 URL도 확인해봐야한다😰 react-router뿐만 아니라 react-icons도 폴더를 찾을 수가 없고, 사소한 문제때문에 고생했다. 다행히 다른 팀원이 앞글자로 폴더 찾으면 된다고 알려줘서 해결했다.. 공식문서 어디에 써있는것인가😢 fontawesome에서도 애먹었는데;; 그래도 또 하나 배웠다!! 해결👏
마크업 작업해야하는데 CSS부터 급하게 하느라 스케줄이 꼬인다. 내일은 약속 있어서 작업 못할 것 같은데... 프로젝트 중에 처음 약속 잡았는데 편하게 쉴 수 있을지는 모르겠다. 그래도 쉬어야 힘이 나지!!



NavLink에서 activeClassName 오류

이러다 다죽어.. 가독성 0%😅
공식문서 보고 했는데 존재하지 않는 타입이라고 떠서 타입스크립트 오류인줄 알았다. 하지만 참고했던 공식문서가 v5버전이었다... 설명으로 사용방법을 잘 모르겠어서 여러 문서를 참고했던게 문제였다. 적용하고 다시 읽어봤더니 정말 다 써있었다. 번역기 말고 늦더라도 영어로 읽어야겠다..

By default, an active class is added to a <NavLink> component when it is active. ... One difference as of v6.0.0-beta.3 is that activeClassName and activeStyle have been removed from NavLinkProps. Instead, you can pass a function to either style or className that will allow you to customize the inline styling or the class string based on the component's active state. You can also pass a function as children to customize the content of the <NavLink> component based on their active state, specially useful to change styles on internal elements.
react-router 공식문서 v6.3 tutorial : NavLink
react-router 공식문서 v6.4.1 : NavLink
react-router 공식문서 v5

-> 두번째 링크의 내용은 v6.4.1와 v6.3가 동일한 내용이다. 튜토리얼을 먼저 읽어보는게 더 이해가 쉬웠다.

요약하면

  • react-router가 v6로 업데이트 되면서 activeClassName이란 속성은 사라지고 style 속성이나 className으로 대체
  • style 속성(props)으로 적용할 때,
    콜백함수의 return값은 CSS정보를 담은 객체

  • className 속성으로 적용할 때에는,
    콜백함수의 return값으로 문자열을 담음


공식문서 링크를 보면 예시 코드는 볼 수 있으니 아래의 내용은 공식문서로 바로 알기 어렵고(초심자 한정이겠지만) 유추해보고, 실제로 되어서 작성한 부분이다.
우선 타입스크립트를 접해보니 Type declaration 토클이 은근 유용했다. 튜토리얼에 나온 코드를 to props 등 임시로 제외하고 style, className 비교부분만 발췌했다.

// 주의! 
// style, className 비교를 위해 일부 생략했습니다. 이것만 쓰면 안돼요!! 

// style에 적용
<NavLink style={({ isActive }) => isActive ? activeStyle : undefined} >Messages</NavLink>

// className에 적용
<NavLink className={({ isActive }) => isActive ? "red" : "blue"} >Messages</NavLink>


// isActive가 true일 때 값을 변수로 설정할 경우(출처는 공식문서) 

//  style에서의 객체 모양 참고 : CSS 아님
//  let activeStyle = {
//    	textDecoration: "underline", <--- 객체: CSS처럼 `;` 아닌 `,` 
//  };

// 	className을 변수로 적용할 때 문자열 : 위에서 "red" 대신 activeClassName 입력
//  let activeClassName = "underline";

공식문서에는 콜백함수의 전달인자의 값으로 구조분해할당으로만 예시가 보였는데, 유명 강사 Maximilian님의 v5 -> v6 차이점 강의를 보니 eventlistener의 콜백함수에서 객체(eventlistener에서는 event객체)를 전달인자로 받아서 값을 추출하는 것처럼 사용할 수도 있었다. 결국은 전달인자로 받을 수 있는 객체의 isActive property에서 boolean 타입으로 활성화 상태임을 알수 있다.

<NavLink className={( navData /** 중괄호 없음*/ ) => {
    return (navData.isActive) ? classes.active : undefined ;
  }} 
	// to= ... 생략
>Home</NavLink>

Maximilian Schwarzmüller 강사님의 v6 영상 참조

코드 아랫부분 이미지에서 입력, 출력값의 타입을 확인해볼수 있다.
isActive 가 false 인 경우 null 보다 undefined 를 적용하자!
공식문서 타입으로 사용법 알아보기


styled-components 적용할 때, NavLink 활성화 클래스 명칭 꿀팁!

참고로 이부분은 공식문서에서 정확하게 언급된 부분은 아니지만 className 이나 style 를 적용하지 않아도 styled components에서 해보니 같은 효과가 발생해서 추가적으로 언급한다. 다시 말하지만 공식적인 것은 아닐 수 있다.

By default, an active class is added to a <NavLink> component when it is active.

공식문서에 이부분 때문에 되지 않을까 한다. 단순하게 반복되는 코드를 쓰기 번거로워서 해보니 되었다. 본인도 되서 당황했지만 좋았다.😜

적용해서 active상태 CSS가 적용되었던 조건

  • styled-components를 사용하여 컴포넌트로 만든 <NavLink />
  • className 이나 style 적용하지 않음
  • 활성화 상태에 적용될 CSS코드를 active 로 설정

NavLink active 클래스명으로 설정하면 className, style 적용 생략도 되는 듯듯

클래스명을 selected로 한 경우는 활성화 안됨

// 오늘자 css까지 입힌 코드(부분 수정 예정)로 참고용입니다.

import styled from "styled-components";
import { useState } from "react";
import { NavLink } from "react-router-dom";
import { MdOutlineLogout, MdOutlineLogin } from "react-icons/md";
import { BiSearchAlt2 } from "react-icons/bi";

const SLogo = styled.img`
  width: 100px;
`;

const SHeader = styled.header`
  height: 60px;
  padding: 0 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;

  span {
    font-size: 0.8rem;
    font-weight: lighter;
    color: var(--gray);
  }
`;

const SNavLink = styled(NavLink)`
  color: var(--gray);
  padding: 0 1.3rem;
  &.active {               <---------- 여기
    color: var(--red);
  }
`;

const Header = () => {
  const [isLogin, setIsLogin] = useState(true); // redux 사용시 변경

  return (
    <SHeader>
      <SLogo src={`${process.env.PUBLIC_URL}/logo.png`} alt="MMZ logo" />
      <section>
        <SNavLink to="/" end>                      <---------- 여기
          HOME
        </SNavLink>
        <span>|</span>
        <SNavLink to="/rank">RANKING</SNavLink>    <---------- 여기
        <span>|</span>
        <SNavLink to="/write">RECIPE</SNavLink>    <---------- 여기
        <span>|</span>
        <SNavLink to="/mypage">MYPAGE</SNavLink>   <---------- 여기
      </section>
      <section className="right">
        {!isLogin ? (
          <SNavLink to="/login">
            <MdOutlineLogin size={25} />
          </SNavLink>
        ) : (
          <SNavLink
            to="/"
            onClick={() => {
              setIsLogin(!isLogin);
            }}
          >
            <MdOutlineLogout size={25} />
          </SNavLink>
        )}
        <SNavLink to="/search">
          <BiSearchAlt2 size={25} />
        </SNavLink>
      </section>
    </SHeader>
  );
};
export default Header;

end : NavLink의 '/' 활성화 문제 해결

위에 코드 전문을 보면

<NavLink to="/" end >Home</NavLink>

/ 에만 end가 들어가있다.

If the end prop is used, it will ensure this component isn't matched as "active" when its descendant paths are matched. For example, to render a link that is only active at the website root and not any other URLs, you can use:

정리하면 end를 넣지 않으면 경로가 /recipe 에도, /login 등에도 / 가 포함되므로 활성화 상태로 표현된다. 그러므로 root path 부분에는 end를 추가로 넣어주면 URL 끝자리가 / 인 경우만 활성화 표시가 된다.

end가 없는 경우 활성화 상태 예시

end가 있는 경우 활성화 상태 예시


react-icons 사용법 : 경로 찾기 등

react-icons 공식문서 Github
react-icons 공식문서
npm : react-icons 공식문서

  • 설치 : npm install react-icons --save

    주의!!! react-icon 이 아니다. s 가 붙은 상태의 모듈을 설치해야한다.
    react-icon으로 설치해도 설치는 된다. version 1.0.0으로... 한참동안 고생을 했다. 지울때는 npm uninstall react-icon 으로 지워주자!


사용법 : import 가져오기

  1. 공식문서에 원하는 아이콘을 검색하여 클릭하면 컴포넌트 이름이 복사된다.

  1. 공식문서 사용법에는 복사된 컴포넌트명칭을 { 복사된이름 } 으로 변수화를 하고, 경로를 입력한다.

    경로는 react-icons/컴포넌트앞자리 로 검색하자!!
    -> 이 부분에 대한 레퍼런스는 찾지 못하고 다른 팀원한테 물어봐서 해결했다.
    어디에 적혀있긴할텐데.. 아시는 분은 댓글 남겨주세요...


  1. JSX 나 TSX 부분에 <컴포넌트이름 /> 으로 사용한다.
    import { FaBeer } from 'react-icons/fa';  
     class Question extends React.Component {
      	render() {
       			 return <h3> Lets go for a <FaBeer />? </h3>
      	}
     }

cf. 타입스크립트 적용시, 추가 모듈을 설치할 필요가 없다.
식자도 설치하려했으나 위에 더이상 지원하지 않는 모듈이라는 문구를 보고 설치하지 않았다. 우선적으로 react-icons가 아닌 react-icon으로 설치되었는지 먼저 확인하는 것을 추천한다.


react-icons 사이즈 조정

<FaBeer size={20} /> 
// px 단위로 숫자만 입력

깃허브 문서에는 다른 방식으로 명시되어있는데 위의 코드처럼해도 같은 효과가 난다.
스텍오버플로우 참고 레퍼런스

깃허브 문서에서 정의된 설정 변경

0개의 댓글