사용자 인터페이스 측면에서 상태에 따라 컴포넌트의 색상 등을 다르게 설정하는 것이 좋다. 그 예시로 Form 이라는 컴포넌트를 만들어서 상태에 따라 동적으로 컴포넌트를 스타일링 하는 방법을 알아보자.
기본적인 JSX는 다음과 같이 설정하였다.
import React from 'react';
const Form = () => {
return (
<form>
<div>
<label>검색어</label>
<input type="text" />
</div>
<button type="submit">검색</button>
</form>
);
};
이제 검색 버튼을 누르면 입력 값을 부모 요소로 전송하는 기능을 추가해보자. 다음과 같이 구현할 수 있다.
import React, { useState } from 'react';
const Form = props => {
const [userInput, setUserInput] = useState('');
const inputChangeHandler = event => {
setUserInput(event.target.value);
};
const formSubmitHandler = event => {
event.preventDefault();
props.onAdd(userInput); // 부모 요소로 전송
setUserInput('');
};
return (
<form onSubmit={formSubmitHandler}>
<div>
<label>검색어</label>
<input
type="text"
onChange={inputChangeHandler}
/>
</div>
<button type="submit">검색</button>
</form>
);
};
마지막으로 동적 컴포넌트 스타일링을 위해 유저의 입력 값이 유효한지 확인하는 state를 추가하고 핸들러에 해당 로직을 추가한다.
const [isValid, setIsValid] = useState(true);
const formSubmitHandler = event => {
event.preventDefault();
// 입력이 공백일 경우 isValid = false
if (userInput.trim().length === 0) {
setIsValid(false);
return;
}
props.onAdd(userInput);
setUserInput('');
};
const inputChangeHandler = event => {
// 입력을 시작한 경우 isValid = true
if (event.target.value.trim().length > 0) {
setIsValid(true);
}
setUserInput(event.target.value);
};
import React, { useState } from "react";
const Form = (props) => {
const [isValid, setIsValid] = useState(true);
const [userInput, setUserInput] = useState("");
const inputChangeHandler = (event) => {
if (event.target.value.trim().length > 0) {
setIsValid(true);
}
setUserInput(event.target.value);
};
const formSubmitHandler = (event) => {
event.preventDefault();
if (userInput.trim().length === 0) {
setIsValid(false);
return;
}
props.onAdd(userInput);
setUserInput("");
};
return (
<form onSubmit={formSubmitHandler}>
<div>
<label>검색어</label>
<input type="text" onChange={inputChangeHandler} />
</div>
<button type="submit">검색</button>
</form>
);
};
export default Form;
이제 동적으로 컴포넌트 스타일을 변경해보자.
가장 간단하게 스타일을 지정할 수 있는 방법이다. JSX 코드만 바꾸면 된다.
// return
<form onSubmit={formSubmitHandler}>
<div>
<label
style={{ color: isValid ? 'black' : 'red' }}
>
검색어
</label>
<input
type="text"
onChange={inputChangeHandler}
style={{
borderColor: isValid ? 'black' : 'red',
background: isValid ? 'transparent' : 'salmon'
}}
/>
</div>
<button type="submit">검색</button>
</form>
로직이 간단하긴 하지만 JSX 코드가 복잡해지고, 매번 isValid를 확인하여 스타일 속성을 정해야 한다는 단점이 있다.
CSS 파일을 별도로 두고 JSX의 className
값을 동적으로 지정하는 방법이다.
.invalid label {
color: red;
}
.invalid input {
border-color: red;
background: salmon;
}
import './Form.css';
// return
<form onSubmit={formSubmitHandler}>
<div className=`${!isValid && 'invalid'}`>
<label>검색어</label>
<input
type="text"
onChange={inputChangeHandler}
/>
</div>
<button type="submit">검색</button>
</form>
별도로 CSS 파일을 만들기 때문에 스타일과 렌더링 로직을 분리할 수 있다는 장점이 있다. 그러나 컴포넌트 단위로 스타일을 관리하는 것이 아니기 때문에 클래스 이름이 겹친다면 CSS 파일을 import 하지 않은 컴포넌트에도 해당 스타일이 적용될수도 있다는 단점이 있다.
기존 CSS를 import 해서 사용하는 방식과 다르게 특정 컴포넌트에만 스타일을 지정하는 방식이다.
기존 div를 다음과 같이 styled-components를 사용하여 InputContainer로 대체할 수 있다.
import { styled } from 'styled-components';
const InputContainer = styled.div`
& label {
color: ${props => (
props.invalid ? 'red' : 'black'
)};
}
& input {
border-color: ${props => (
props.invalid ? 'red' : 'black'
)};
background: ${props => (
props.invalid ? 'salmon' : 'transparent'
)};
}
`;
// return
<form onSubmit={formSubmitHandler}>
<InputContainer>
<label>검색어</label>
<input
type="text"
onChange={inputChangeHandler}
/>
</InputContainer>
<button type="submit">검색</button>
</form>
개발자 도구를 확인해보면 class 명이 고유한 해시값을 가지는 것을 알 수 있다. 즉 특정 컴포넌트에만 스타일이 적용된다.
특정 컴포넌트에만 스타일을 적용하되 스타일 관련 로직을 별도의 모듈 파일로 관리하는 방법이다.
파일명.module.css
로 스타일을 작성한다.
.invalid label {
color: red;
}
.invalid input {
border-color: red;
background: salmon;
}
CSS 모듈을 적용하기 위해 다음과 같이 모듈의 styles
를 import 한다.
import styles form '.Form.module.css';
// return
<form onSubmit={formSubmitHandler}>
<div className=`${!isValid && styles.invalid}`>
<label>검색어</label>
<input
type="text"
onChange={inputChangeHandler}
/>
</div>
<button type="submit">검색</button>
</form>
CSS 모듈을 사용할 경우 클래스명은 다음과 같다. 컴포넌트이름_클래스이름__고유해시값
즉, (2)번 방식과 비슷하지만 그 적용 범위가 컴포넌트로 국한된다는 차이가 있다.