리액트에서 DOM 요소에 class명을 사용하는 법
기본적으로 html에서 div, span 등 DOM 요소들에는 특정 class명을 붙여서 원하는 스타일을 적용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
<style>
.box-info{
text-align: center;
}
.mg-10{
margin: 10px;
}
</style>
...
<div class="box-info">
</div>
위의 코드는 class명이 box-info
인 DOM 요소에 들어가는 텍스트에 가운데(text-align: center)
정렬 스타일이 적용된 상황입니다.
class명은 아래와 같이 여러 개를 붙일 수도 있습니다.
1
2
<div class="box-info mg-10">
</div>
리액트에서는 class를 사용하지 않고 대신 JSX 문법으로 className을 사용합니다.
참고 링크 : https://ko.reactjs.org/docs/introducing-jsx.html
JSX는 HTML보다는 JavaScript에 가깝기 때문에, React DOM은 HTML 어트리뷰트 이름 대신
camelCase
프로퍼티 명명 규칙을 사용합니다. 예를 들어, JSX에서class
는className
가 되고tabindex
는tabIndex
가 됩니다.
그래서 리액트에서는 다음과 같이 className
을 사용해서 클래스명을 추가합니다.
1
2
3
4
5
...
return (
<div className="box-info">
</div>
);
클래스를 여러 개 추가할 때에도 기존에 html에서 작성하듯이 하면 됩니다.
1
2
3
4
5
...
return (
<div className="box-info mg-10">
</div>
)
classnames 모듈 사용하기
이제 소개할 classnames
모듈은 여러 클래스를 추가할 때 뿐만 아니라, 특정 값이 true/false임에 따라 클래스명을 추가하거나, 추가하지 않도록 하는 것을 간단히 구현할 수 있게 해 줍니다.
먼저
npm install classnames
혹은yarn add classnames
명령어를 입력해 모듈을 설치해 주세요.
classnames : https://www.npmjs.com/package/classnames
예를 들어 다음과 같은 코드가 있다고 가정해 봅니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import './styles';
import classnames from 'classnames';
const TestComponent = (props) => {
const {data, description} = props;
const valid = data.find(item => item.text === 'abc');
return (
<div className={classnames('box-info', {mg-10: valid})}>
{description}
</div>
);
}
export default TestComponent;
props로 받아온 data, text값을 활용하여 렌더링하는 TestComponent
컴포넌트 입니다.
valid
에는 find
메소드의 판별식을 만족한 가장 첫 번째 요소를 반환받습니다. 만족하는 값이 없다면 undefined
가 저장됩니다.
여기서는 data
객체의 text
프로퍼티에 abc라는 값이 있을 때만 valid에 값이 저장됩니다.
위에서 classnames를 적용한 부분을 보겠습니다.
1
2
3
4
5
return (
<div className={classnames('box-info', {mg-10: valid})}>
{description}
</div>
)
classnames를 활용하여 작성한 형태는 위와 같습니다.
box-info
클래스는 조건없이 기본으로 추가하고, mg-10
클래스는 valid
값이 true
로 평가되는 경우에만 추가됩니다.
자바스크립트에서는 undefined
, 0(number)
, ""(string)
들은 boolean 비교 시 false
값으로 알아서 간주합니다.
따라서 valid에 undefined
가 저장되어 있다면, false
로 평가되므로 mg-10
클래스명을 추가하지 않게 됩니다.
undefined
가 아닌 특정한 값이 저장되어 있다면 ture
로 평가되므로 mg-10
클래스명을 추가합니다.
이렇게 classnames를 활용하면, 위처럼 key(class명) : value 형태로 value가 true 혹은 false
로 평가됨에 따라 지정한 스타일을 손쉽게 적용하거나, 적용하지 않을 수 있습니다.
참고사항 - !! 연산자가 권장된 사용법은 아니다
자바스크립트에서는 undefined
, 0(number)
, ""(string)
들을 boolean 비교 시 false
값으로 알아서 간주합니다.
그래서 사실 강제로 boolean 타입으로 만드는 !!
연산자가 권장되는 표기법은 아닙니다.
1
2
3
4
5
return (
<div className={classnames('box-info', {mg-10: !!valid})}>
{description}
</div>
)
굳이 위 코드처럼 !!valid
로 표현하지 않아도, valid에 undefined
가 있었다면 처리할 때 falsy value 이므로 무시되기 때문입니다.
추가적으로 불필요하게 사용되는 예시 중 하나만 언급해 보도록 하겠습니다.
예를 들어 숫자 0인 값이 파라미터로 들어왔다고 가정해 보겠습니다. 개발자는 함수의 파라미터 값이 과연 정의되지 않은 값인지 체크하고 싶었는데, 아래와 같이 코드를 작성했으면 어떨까요?
1
2
3
4
5
function test(param){
if (!!param) return "success";
return "fail";
}
if에 들어오는 조건문은 이미 그 자체로 true, false 값이 평가가 됩니다. 하지만 위 코드는 그 부분에 불필요하게 !!
연산자가 사용된 것입니다.
1
2
3
4
5
// (1) 불필요한 !!와 삼항 연산자
{ !!isRender ? <MoreButton/> : null }
// (2) 삼항 연산자와 !!를 제거하고 단순하게 &&로 표현한 모습
{ isRender && <MoreButton/> }
위 코드에서도 !!는 불필요하게 사용된 것이며, 어차피 리액트는 null, undefined, true, false 등의 값은 렌더링하지 않으므로 jsx 코드에서 (1)과 같이 작성하는 것은 불필요합니다.
정리하면 로직상 꼭 !!
연산자를 사용하지 않아도 되는 경우에는, 사용하지 않는 편이 낫다는 것이 많은 사람들의 의견입니다. (반드시 사용하지 말라는 의미는 아닙니다.)
이 외에도 !! 에 대해 불필요하게 사용된 예시를 확인하시려면 아래 링크를 추천드립니다.
참고하면 좋은 링크 : The Double-Bang (!!) Operator And A Misunderstanding Of How JavaScript Handles Truthy / Falsy Values
마지막으로 classnames를 활용하는 예시 케이스들을 정리하면 아래와 같습니다. (꼭 조건을 사용하지 않더라도 여러 개 클래스명을 붙이는 역할을 할 수도 있습니다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
className={classnames('box-info', 'mg-10')} // 'box-info mg-10'
className={classnames(['box-info', 'mg-10'])} // 'box-info mg-10'
className={classnames('box-info', {mg-10 : false})} // 'box-info'
className={classnames('box-info', {mg-10 : null})} // 'box-info'
className={classnames('box-info', {mg-10 : undefined})} // 'box-info'
className={classnames('box-info', {mg-10 : true})} // 'box-info mg-10'
className={classnames('box-info', {mg-10 : 'abc'})} // 'box-info mg-10'
참고사항 : classnames에서 { key : value } 값을 사용할 때 value의 true/false 설명과 관련하여 부정확한 설명이 있어서 일부 수정하였습니다(21.7.29).