[TIL] 엘리스 SW 엔지니어 트랙 Day 053
글 작성자: 망고좋아
반응형
📖 오늘 배운 내용 - 2022.01.05
- CSS import
- CSS module
- CSS-in-js
- Sass
- Flexbox
- styled-components
📝 좋은 앱을 만들려면?
- 번들 사이즈에 대한 고려
- CSS 코드가 차지하는 사이즈는 무척 중요한 요소.
- 앱 성능에 대한 고려
- animation, transition 등 유저와의 상호작용에서 스타일 코드의 성능이 중요 요소.
- 사용자에게 유리한 UI/UX를 고려
- 스타일링에 대한 지식으로, 고급 테크닉을 적용하여 더 나은 UI/UX를 반영
- 자바스크립트를 이용한 다양한 스타일 기법
- UI 토글링, 애니메이션, 다크 모드, 복잡한 UI 컴포넌트 등은 자바스크립트에 대한 지식만으로 구현하기 힘듦.
- 유지보수가 용이하고 확장 가능한 코드를 작성
- 스타일에 관련된 코드를 어떻게 작성하고 관리하는가에 대한 지식이 필요
📝 React 앱에서의 스타일링 방법
📝 CSS Box Model - box-sizing
📝 Sass 맛보기
📝 Flexbox
flex: flex-grow flex-shrink flex-basis
flex: 0 0 120px
flex: 1
⇒flex: 1 1 auto
📝 styled-components
📕 styled-components를 이용해 회원가입 폼 구현하기
import React, { useState } from "react";
import "./register-form.css";
import styled, { css } from 'styled-components';
const InputStatus = {
NORMAL: "normal",
ERROR: "error",
SUCCESS: "success",
};
function RegisterForm() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
const [nameError, setNameError] = useState(null);
const [ageError, setAgeError] = useState(null);
const [nameInputStatus, setNameInputStatus] = useState(InputStatus.NORMAL);
const [ageInputStatus, setAgeInputStatus] = useState(InputStatus.NORMAL);
const handleNameChange = (e) => {
setName(e.target.value);
};
const handleAgeChange = (e) => {
setAge(e.target.value);
};
const validateName = (name) => {
if (name.length < 1 || name.length > 10) {
setNameError("이름은 1글자 이상, 10글자 이하여야 합니다.");
setNameInputStatus(InputStatus.ERROR);
return;
}
setNameInputStatus(InputStatus.SUCCESS);
};
const validateAge = (age) => {
const numberedAge = Number(age);
if (numberedAge < 1 || numberedAge > 100) {
setAgeError("나이는 1부터 100 사이여야 합니다.");
setAgeInputStatus(InputStatus.ERROR);
return;
}
setAgeInputStatus(InputStatus.SUCCESS);
};
const validateForm = (form) => {
validateName(form.name);
validateAge(form.age);
};
const handleSubmit = () => {
const formData = { name, age };
validateForm(formData);
};
const handleReset = () => {
setName("");
setAge("");
};
const getInputStatusStyle = (status) => {
if (status === InputStatus.ERROR) {
return "input-invalid";
} else if (status === InputStatus.SUCCESS) {
return "input-valid";
}
return "";
};
return (
<FormContainer>
<FormFieldset>
<FormLabel
error={nameInputStatus === InputStatus.ERROR}
htmlFor="name"
>
이름
</FormLabel>
<FormInput
value={name}
id="name"
onChange={handleNameChange}
type="text"
name="name"
status={nameInputStatus}
placeholder="이름을 입력해 주세요."
/>
<FormError>
{nameInputStatus === InputStatus.ERROR && nameError}
</FormError>
</FormFieldset>
<FormFieldset>
<FormLabel
error={ageInputStatus === InputStatus.ERROR }
htmlFor="age"
>
나이
</FormLabel>
<FormInput
id="age"
value={age}
onChange={handleAgeChange}
type="number"
name="age"
status={ageInputStatus}
placeholder="나이를 입력해 주세요."
/>
<FormError>
{ageInputStatus === InputStatus.ERROR && ageError}
</FormError>
</FormFieldset>
<ButtonContainer>
<FormButton
onClick={handleReset}
type="button"
buttonType="reset"
>
초기화
</FormButton>
<FormButton
onClick={handleSubmit}
type="button"
buttonType="submit"
>
제출
</FormButton>
</ButtonContainer>
</FormContainer>
);
}
export default RegisterForm;
const TextError = css`
color: #ff6b6b;
`
const InputInvalid = css`
border: 2px solid #ff6b6b;
`
const InputValid = css`
border: 2px solid #51cf66;
`
const resetButton = css`
background: #adb5bd;
`
const submitButton = css`
background: #37b24d;
`
const FormContainer = styled.form`
min-width: 300px;
`;
const FormFieldset = styled.fieldset`
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
border: none;
padding: 12px 0;
&:not(:first-of-type) {
border-bottom: none;
border-top: 1px solid rgba(0, 0, 0, 0.3);
}
`
const FormLabel = styled.label`
display: block;
padding-bottom: 8px;
font-size: 0.8rem;
color: gray;
${props => props.error && TextError}
`;
const FormInput = styled.input`
display: block;
padding: 4px;
border: 2px solid #dee2e6;
border-radius: 3px;
${({ status }) => status === InputStatus.ERROR && InputInvalid}
${({ status }) => status === InputStatus.SUCCESS && InputValid}
`
const FormError = styled.div`
font-size: 0.8rem;
min-height: 20px;
margin-top: 4px;
color: #ff6b6b;
`
const ButtonContainer = styled.div`
display: flex;
`;
const FormButton = styled.button`
flex: 1;
border: none;
padding: 4px;
color: white;
font-weight: 700;
border-radius: 3px;
cursor: pointer;
&:not(:first-of-type) {
margin-left: 8px;
}
${({ buttonType }) => buttonType === "reset" && resetButton }
${({ buttonType }) => buttonType === "submit" && submitButton }
`;
💡 오늘 깨달은 것
- modal을 구현할 때는 absolute보다 fixed를 사용하는 게 좋다.
- em은 부모 폰트 사이즈의 상대적인 크기를 나타내는 unit
- sass를 들어만 봤지 어떤 장점을 제공하는지 몰랐는데 이번 수업을 통해서 관심이 많이 생겼다. 생산성이 높아질 거 같다.
- styled-componets를 사용하니까 더욱 리액트스러워졌다. 다만 좀 더 공부해야겠다.
📌 참고
반응형
'프로그래밍 > Today I Learned' 카테고리의 다른 글
[TIL] 엘리스 SW 엔지니어 트랙 Day 055 (0) | 2022.01.13 |
---|---|
[TIL] 엘리스 SW 엔지니어 트랙 Day 054 (0) | 2022.01.13 |
[TIL] 엘리스 SW 엔지니어 트랙 Day 052 (0) | 2022.01.10 |
[TIL] 엘리스 SW 엔지니어 트랙 Day 051 (0) | 2022.01.03 |
[TIL] 엘리스 SW 엔지니어 트랙 Day 050 (0) | 2022.01.03 |
댓글
이 글 공유하기
다른 글
-
[TIL] 엘리스 SW 엔지니어 트랙 Day 055
[TIL] 엘리스 SW 엔지니어 트랙 Day 055
2022.01.13 -
[TIL] 엘리스 SW 엔지니어 트랙 Day 054
[TIL] 엘리스 SW 엔지니어 트랙 Day 054
2022.01.13 -
[TIL] 엘리스 SW 엔지니어 트랙 Day 052
[TIL] 엘리스 SW 엔지니어 트랙 Day 052
2022.01.10 -
[TIL] 엘리스 SW 엔지니어 트랙 Day 051
[TIL] 엘리스 SW 엔지니어 트랙 Day 051
2022.01.03