리액트로 웹앱을 구축할 때, 단지 컴포넌트를 구상하는 것 뿐만 아니라 로직이 제대로 작동하도록 해야 한다.
리액트 앱을 구축하는 것은 또한 앱을 스타일링 하는 것이기도 하다. 스타일링은 컴포넌트를 구축하는데 있어서 아주 중요한 부분이기도 하다.
🎯 목표
조건부로 혹은 동적인 방법(Conditional @ Dynamic Styles)으로 스타일을 설정하는 방법에 대해 알아보자.
(ex. 사용자가 유효하지 않은 입력값을 넣으면 입력 필드가 빨간색으로 표시됨)
1. styled Components
서드 파티 라이브러리인 styled Components를 통해, 고유한 범위를 가진 스타일로 미리 스타일이 지정된 컴포넌트 설정할 수 있다.
2. css modules
현재 사용자가 공백만 입력하더라도 투두리스트에 항목이 추가가 되고 있다. 이를 고치기 위해 공백으로 입력시 추가하지 못하게 만들어보자. 그리고 그에 더해 공백만 입력할 경우 사용자에게 유효하지 않음을 표시할 수 있도록 스타일을 바꿔보자.
먼저 공백으로 입력시 추가하지 못하게, 폼에서 입력 값의 길이를 체크하여 이 값이 유효한지 체크한다.
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
};
enteredValue.trim().length === 0
trim()
메소드를 사용하여 사용자가 공백만 입력하여 입력값이 비었으면, 유효하지 않기 때문에 isValid
의 상태를 false
로 바꿔 주고, 반환return
하여 함수 실행을 중단시키면 된다.
trim()
메소드는 시작이나 끝 부분에 과도하게 쓰인 공백 제거해주는 메소드로, 사용자가 수많은 공백(띄워쓰기만)을 입력한 경우 유효성을 배제하기 위해 사용할 수 있다.
사용자에게 피드백 주기 위해, 입력값이 유효하지 않은 경우 입력 부분에 빨간색 테두리와, 연한 빨간색 바탕 추가하고, 레이블도 빨간색으로 바뀌게 해보자.
state
를 사용하면된다. state는 사용자가 입력한 것이 유효한지 나타내는 지표가 되므로 불리언으로 작업하면 된다.isValid
의 상태가 false
일때, 사용자에게 시각적으로 유효하지 않다는 표시를 주기 위해 스타일을 적용한다.style={{ color: !isValid ? "red" : "black" }}
isValid
가 false여서 !isValid
가 true가 될때만 "red"
가 되도록 작성하면 된다.import React, { useState } from "react";
import Button from "../../UI/Button/Button";
import "./CourseInput.css";
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = useState("");
const [isValid, setIsValid] = useState(true);
const goalInputChangeHandler = (event) => {
//2. 입력 값이 다시 유효해져야 하기 때문에, 리셋 기능을 설정하기 위해 모든 키 입력에 반응하는 위치로 가야 한다.
if (event.target.value.trim().length > 0) {
//입력값이 유효하다면 isValid상태를 true로 설정하여
setIsValid(true);
}
setEnteredValue(event.target.value);
};
const formSubmitHandler = (event) => {
event.preventDefault();
/*
1. 공백으로 입력시 목표 추가 못하게 하기
입력된 값이 유효한지 체크 먼저 해야함
trim()메소드는 시작이나 끝 부분에 과도하게 쓰인 공백 제거해주는 메소드
사용자가 수많은 공백(띄워쓰기만)을 입력한 경우 배제하기 위해 사용함
*/
//길이 체크
if (enteredValue.trim().length === 0) {
/*
입력값이 비었으면 그냥 반환해서 함수 실행 중단시키기
사용자에게 피드백 주기 위해
입력 부분에 빨간색 테두리와, 연한 빨간색 바탕 추가하고, 레이블도 빨간색으로 바뀌게 하기
*/
//state를 사용하면 된다. 그 state는 사용자가 입력한 것이 유효한지 나타내는 지표가 되므로 불리언으로 작업하자.
setIsValid(false);
//isValid가 false면 스타일 적용
// 쉬운 방법 1. 레이블에 inline으로 객체 추가하기
//style={{ color: !isValid ? "red" : "black" }}
//isValid가 false여서 !isValid가 true가 될때만 "red"가 되도록
//하지만 이렇게 inline으로 작성하면, css에 최우선 순위를 두기 때문에 우리의 모든 스타일을 오버라이드한다.
return;
}
props.onAddGoal(enteredValue);
};
return (
<form onSubmit={formSubmitHandler}>
<div className="form-control">
<label style={{ color: !isValid ? "red" : "black" }}>Course Goal</label>
<input
style={{
borderColor: !isValid ? "red" : "",
backgroundColor: !isValid ? "salmon" : "transparent",
}}
type="text"
onChange={goalInputChangeHandler}
/>
</div>
<Button type="submit">Add Goal</Button>
</form>
);
};
export default CourseInput;
동적으로 css class를 설정하기 위해 먼저 css 파일에 원하는 스타일을 추가한다.
.form-control.invalid input {
border-color: red;
background-color: #ffd7d7;
}
.form-control.invalid label {
color: red;
}
.form-control.invalid
form-control
이 invalid
클래스에 접근 가능하다고 선언한다..form-control.invalid input{}
이 css가 효과를 가지려면 invalid 클래스가 동적으로 추가되어야 한다.
css 파일에 추가해둔 클래스를 상태에 따라 div 요소에 추가한다.
return (
<form onSubmit={formSubmitHandler}>
<div className={`form-control ${!isValid ? "invalid" : ""}`}>
<label>Course Goal</label>
<input type="text" onChange={goalInputChangeHandler} />
</div>
<Button type="submit">Add Goal</Button>
</form>
);
<div className={}>
<div className={``}>
<div className={`form-control ${!isValid ? "invalid" : ""}`}
${}
를 작성하고 중괄호 사이에 컨텐츠를 넣으면 문자열에 동적인 값을 주입할 수 있다.이 방법은 css파일로 작업할 때, 클래스만으로도 작업할 수 있는 방법이다.
간단한 구문으로 동적으로 클래스를 추가하거나 삭제할 수 있어 편리하다.
DOM에서 클래스를 추가하거나 제거하는 것은 리액트가 하는 일이다.
내가 할 일은,
그러면 리액트는 그에 맞춰 업데이트 해준다.
백틱안에 props을 사용하면 스타일을 손쉽게 동적으로 바꿀 수 있다.
<FormControl invalid={!isValid}>
import React, { useState } from "react";
import Button from "../../UI/Button/Button";
//import "./CourseInput.css";
import styled from "styled-components";
//JSX에서 컴포넌트로 사용할 것이기 때문에 대문자로 작성
//스타일 컴포넌트 패키지 사용: JSX의 div 부분 대체
//스타일컴포넌트에 전달되는 일부 props에 따라 스타일을 동적으로 바꿀 수 있다.
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;
}
`;
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = useState("");
const [isValid, setIsValid] = useState(true);
const goalInputChangeHandler = (event) => {
//2. 입력 값이 다시 유효해져야 하기 때문에, 리셋 기능을 설정하기 위해 모든 키 입력에 반응하는 위치로 가야 한다.
if (event.target.value.trim().length > 0) {
//입력값이 유효하다면 isValid상태를 true로 설정
setIsValid(true);
}
setEnteredValue(event.target.value);
};
const formSubmitHandler = (event) => {
event.preventDefault();
//1. 공백으로 입력시 목표 추가 못하게 하기: 길이 체크
if (enteredValue.trim().length === 0) {
//입력값이 비었으면 그냥 반환해서 함수 실행 중단시키.
//사용자가 입력한 것이 유효한지 나타내는 지표가 되는 state를 불리언으로 사용
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
};
return (
<form onSubmit={formSubmitHandler}>
//🔥
<FormControl invalid={!isValid}>
<label>Course Goal</label>
<input type="text" onChange={goalInputChangeHandler} />
</FormControl>
<Button type="submit">Add Goal</Button>
</form>
);
};
export default CourseInput;