만약 사용자가 아무것도 작성하지 않거나 공백만 작성했을 때 제출버튼을 누르면 label과 입력창의 색을 빨간색으로 보이게 하고싶다.
<label style={{ color: !isValid ? 'red' : 'black' }}>Course Goal</label>
<input
type="text"
onChange={goalInputChangeHandler}
style={{ borderColor: !isValid ? 'red' : 'black', background: !isValid ? 'salmon' : 'transparent' }}
/>
하지만 inline 요소로 style을 작성하면 기존에 css에 작성했던 style을 잡아먹어 버리는 단점이 있다.
label과 input을 감싸는 div 태그에 입력이 유효하지 않을 때만 invalid라는 클래스가 추가되도록 해보자.
css에서 .form-control.invalid
라고 작성을 하면 form-control이 invalid 클래스에 접근 가능하다고 선언하는 것이다.
.form-control.invalid input {
border-color: red;
background: #ffd7d7;
}
.form-control.invalid label {
color: red;
}
div 태그의 class가 동적으로 설정되어야 하므로 중괄호로 설정하고, 백틱 안에 ${}를 써서 자바스크립트 표현식을 넣는다.
<div className={`form-control ${!isValid ? 'invalid' : ''}`}>
css가 import된 파일에서 뿐만 아니라 해당 클래스를 갖고 있다면 전체 페이지에 있는 모든 요소에 적용된다.
해결방법
npm install --save styled-components
styled components 임포트
import styled from 'styled-components'
태그드 템플릿 리터럴
const Button = styled.button``
자바스크립트의 기본 기능
button이 styled 객체의 메소드이고, 괄호를 사용해서 호출하지 않고 백틱을 붙인다.
styled는 모든 html 요소에 대한 메소드를 갖고 있다.
이것은 뒷단에서 메소드로 실행된다.
백틱사이에 전달하는 것이 Button 메소드로 가고, button 메소드가 새로운 button 컴포넌트를 반환한다.
const Button = styled.button`
font: inherit;
padding: 0.5rem 1.5rem;
border: 1px solid #8b005d;
color: white;
background: #8b005d;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
cursor: pointer;
&:focus {
outline: none;
}
&:hover,
&:active {
background: #ac0e77;
border-color: #ac0e77;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}
`;
이제 디폴트로 반환되는 button은 여기서 설정한 button 컴포넌트로 전달하는 모든 props를 적용한다.
개발자 도구에 가면 처음보는 class가 두개 있는데, style-components 패키지에 의해 동적으로 생성된 클래스 이름이다.
모든 클래스가 고유한 이름을 갖기 때문에 앱에 있는 다른 컴포넌트에 영향을 주지 않는다.
동적 props invalid를 가지는 div에 style components를 적용해보자.
styled 컴포넌트 함수에 의해 반환되는 컴포넌트가 그 아래 컴포넌트에 props를 전달한다.
동적 props를 가지는 방법 1
invalid라는 클래스를 넣었다뺐다
const FormControl = styled.div`
margin: 0.5rem 0;
& label {
font-weight: bold;
display: block;
margin-bottom: 0.5rem;
}
& input {
display: block;
width: 100%;
border: 1px solid #ccc;
font: inherit;
line-height: 1.5rem;
padding: 0 0.25rem;
}
& input:focus {
outline: none;
background: #fad0ec;
border-color: #8b005d;
}
&.invalid input {
border-color: red;
background: #ffd7d7;
}
&.invalid label {
color: red;
}
`;
<FormControl className={!isValid && 'invalid'}>
동적 props를 가지는 방법 2
invalid라는 속성을 보내주기
const FormControl = styled.div`
margin: 0.5rem 0;
& label {
font-weight: bold;
display: block;
margin-bottom: 0.5rem;
color: ${(props) => (props.invalid ? 'red' : 'black')};
}
& input {
display: block;
width: 100%;
border: 1px solid ${(props) => (props.invalid ? 'red' : '#ccc')};
background: ${(props) => (props.invalid ? '#ffd7d7' : 'transparent')};
font: inherit;
line-height: 1.5rem;
padding: 0 0.25rem;
}
& input:focus {
outline: none;
background: #fad0ec;
border-color: #8b005d;
}
`;
<FormControl invalid={!isValid}>
작은 장치(화면)에서 버튼이 전체 너비를 차지하게 만들어보자.
const Button = styled.button`
width: 100%;
font: inherit;
padding: 0.5rem 1.5rem;
border: 1px solid #8b005d;
color: white;
background: #8b005d;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
cursor: pointer;
@media (min-width: 768px) {
width: auto;
}
&:focus {
outline: none;
}
&:hover,
&:active {
background: #ac0e77;
border-color: #ac0e77;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
}
`;
https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/
css 파일에 이름을 지정해서 import한다.
css 파일 이름에 .module을 붙인다.
import styles from './Button.module.css';
styles는 객체이고 그 객체 안에 있는 클래스를 프로퍼티로 갖게 된다.
<button type={props.type} className={styles.button} onClick={props.onClick}>
개발자 도구를 가보면 class 이름이 컴포넌트이름_클래스이름__고유한해시값
으로 구성되어있다.
css 모듈은 모든 컴포넌트에 대해서 여기서 임포트하고 있는 모든 클래스의 이름을 바꿔 모든 css 파일을 고유하게 만든다.
css 모듈은 css 파일에서 설정한 css 스타일의 범위가 이 파일에 임포트하는 컴포넌트에 한정된다는 것을 확실하게 해준다.
프로퍼티 이름이 form-control이라서 유효하지 않다면 대괄호를 사용하고 작은 따옴표로 이름을 감싸준다.
<div className={styles['form-control']}>
동적 클래스 추가
변환된 클래스 이름 입력
<div className={`${styles['form-control']}`}>
동적 클래스 입력
<div className={`${styles['form-control']} ${!isValid && styles.invalid}`}>
css 모듈에서 미디어 쿼리 설정
@media (min-width: 768px) {
.button {
width: auto;
}
}