-
[인사정보] input,유효성 확인, dropDown, 하단창React/과제 테스트 2023. 8. 9. 21:26
🐇 input - map으로 반복 및 에러 창
이름, 이메일, 닉네임을 각각 input 태그로 입력받고 나열하여 보여준다.
이름, 이메일, 닉네임에 대해서는 유효성 확인이 필요합니다.1. 배열 나열 - key
{["name", "email", "nickname"].map((v) => (<div key={v} style={{ position: "relative" }}><Inputvalue={eval(v)}onChange={(event) =>changeValue(event, v as keyof typeof typeToKorean)}type={v as keyof typeof typeToKorean}/></div>))}2. 입력값이 잘못 되었을 경우 input 아래 유효성 확인한다.
🥕 유효성 검사
※ 객체 키값 타입 - keyof typeof {}
- typeof : 객체 데이터를 객체 타입으로 변환해주는 연산자
type Fruit = { red: string; yellow: string; green: string; } - keyof : 객체 형태의 타입을, 따로 속성들만 뽑아 모아 유니온 타입으로 만들어주는 연산자
type Union = keyof Type; // type Union = name | age | married
※ Regex - regexp.test(검사필요한 변수)
표현식의미^x문자열의 시작을 표현하며 x 문자로 시작됨을 의미한다. x$문자열의 종료를 표현하며 x 문자로 종료됨을 의미한다. .x임의의 한 문자의 자리수를 표현하며 문자열이 x 로 끝난다는 것을 의미한다. x+반복을 표현하며 x 문자가 한번 이상 반복됨을 의미한다. x?존재여부를 표현하며 x 문자가 존재할 수도, 존재하지 않을 수도 있음을 의미한다. x*반복여부를 표현하며 x 문자가 0번 또는 그 이상 반복됨을 의미한다. x|yor 를 표현하며 x 또는 y 문자가 존재함을 의미한다. (x)그룹을 표현하며 x 를 그룹으로 처리함을 의미한다. (x)(y)그룹들의 집합을 표현하며 앞에서 부터 순서대로 번호를 부여하여 관리하고 x, y 는 각 그룹의 데이터로 관리된다. (x)(?:y)그룹들의 집합에 대한 예외를 표현하며 그룹 집합으로 관리되지 않음을 의미한다. x{n}반복을 표현하며 x 문자가 n번 반복됨을 의미한다. x{n,}반복을 표현하며 x 문자가 n번 이상 반복됨을 의미한다. x{n,m}반복을 표현하며 x 문자가 최소 n번 이상 최대 m 번 이하로 반복됨을 의미한다. 표현식의미[xy]문자 선택을 표현하며 x 와 y 중에 하나를 의미한다. [^xy]not 을 표현하며 x 및 y 를 제외한 문자를 의미한다. [x-z]range를 표현하며 x ~ z 사이의 문자를 의미한다. \^escape 를 표현하며 ^ 를 문자로 사용함을 의미한다. \bword boundary를 표현하며 문자와 공백사이의 문자를 의미한다. \Bnon word boundary를 표현하며 문자와 공백사이가 아닌 문자를 의미한다. \ddigit 를 표현하며 숫자를 의미한다. \Dnon digit 를 표현하며 숫자가 아닌 것을 의미한다. \sspace 를 표현하며 공백 문자를 의미한다. \Snon space를 표현하며 공백 문자가 아닌 것을 의미한다. \ttab 을 표현하며 탭 문자를 의미한다. \vvertical tab을 표현하며 수직 탭(?) 문자를 의미한다. \wword 를 표현하며 알파벳 + 숫자 + _ 중의 한 문자임을 의미한다. \Wnon word를 표현하며 알파벳 + 숫자 + _ 가 아닌 문자를 의미한다.
정규표현식을 사용할 때 Flag 라는 것이 존재하는데 Flag를 사용하지 않으면 문자열에 대해서 검색을 한번만 처리하고 종료하게 된다. Flag는 다음과 같은 것들이 존재한다.Flag의미gGlobal 의 표현하며 대상 문자열내에 모든 패턴들을 검색하는 것을 의미한다. iIgnore case 를 표현하며 대상 문자열에 대해서 대/소문자를 식별하지 않는 것을 의미한다. mMulti line을 표현하며 대상 문자열이 다중 라인의 문자열인 경우에도 검색하는 것을 의미한다. const validateField = (type: keyof typeof typeToKorean,value: string): string => {if (value.trim() === "") {return `${typeToKorean[type]}을(를) 입력해주세요.`;}
const errorMessage = checkValidata(type) || "";// todo : setErrors(...)return errorMessage;};
const checkValidata = (type: keyof typeof typeToKorean) => {if (type === "name") {const nameRegex = /^[가-핳]{2,4}$/;if (!nameRegex.test(name)) {console.log("FN", name);return "2~4글자의 한글만 입력이 가능합니다.";}} else if (type === "email") {const emailRegex = /^[a-zA-Z0-9]+@grepp\.co$/;if (!emailRegex.test(email)) {console.log("email", email);return `이메일 ID는 영문(대소문자 구분 없음)과 숫자만 입력이 가능\n하며, @grepp.co 형식의 이메일만 입력이 가능합니다.`;}// 정규식 ^[a-zA-Z0-9]+@grepp\.co$는 이메일 주소가 영문 대소문자와 숫자로만 이루어져 있어야 하며,// 그 뒤에 @grepp.co가 붙는 형식을 나타냅니다. 따라서 특수문자가 포함되지 않도록 되어있으며,//특수문자를 입력하면 유효하지 않은 이메일 형식으로 처리될 것입니다.} else {const nicknameRegex = /^[a-zA-Z]{3,10}$/;if (!nicknameRegex.test(nickname)) {console.log("NIC", nickname);return "대소문자 구분 없이 3~10 글자의 영문만 입력이 가능합니다.";}}};3. 에러 메시지가 있을 경우 보여준다.
※ useState
const [test, setTest] = useState([]); // ...
setTest((prev) => [...prev, newValue]);const changeValue = (event: React.ChangeEvent<HTMLInputElement>,type: keyof typeof typeToKorean) => {const errorMessage = validateField(type, event.target.value);
// 에러 메시지 업데이트setErrors((prevErrors) => ({...prevErrors,[type]: errorMessage,}));
console.log(type);if (type === "name") {setName(event.target.value);} else if (type === "email") {setEmail(event.target.value);} else if (type === "nickname") {setNickname(event.target.value);} else if (type === "role") {setRole(event.target.value);} else if (type === "mbti") {setMbti(event.target.value);}checkValidata(type);};4. error 창 css 설정
🥕 말풍선 모양
※ transform
transform : 요소에 회전, 크기 조절, 기울이기, 이동 효과를 부여할 수 있다.
아무것도 적용되지 않은 기본값은 none 이다.scale(sx,sy) : 2D로 크기를 조절하는 transform 함수이다.
transform: scale(0.5);
rotate : 회전을 나타내는 transform 함수이다.
transform: rotate(45deg);
translate() : 이동을 담당하는 transform 함수이다.
transform: translate(100px, 30%);
skew() : 기울임(왜곡) 변형을 나타내는 transform 함수이다.
transform: skew(20deg, 20deg);
a. 부모 div
position: "relative"b. 에러창 스타일 설정
.inputError {background-color: white;padding: 6px 12px;border-radius: 4px;top: -5px;width: 280px;/* top: 14%;left: 50%; */font-size: 14px;white-space: nowrap;font-size: 12px;position: relative;border: 1px solid black;border-radius: 10px;}c. 말풍선 처럼 보이게
- position: absolute;
.inputError:after {border-top: 10px solid transparent;border-left: 10px solid transparent;border-right: 10px solid transparent;border-bottom: 10px solid #484848;content: "";position: absolute;top: -20px;left: 4%;}참고로 ) bottom-top : top : 역삼각형
🐇 Dropdown
드롭다운 형식
1. dropDown 컴포넌트 작성
import React, { useState } from "react";
interface DropDownProps {label?: string;list: string[];selected: string;dropDownPlaceHolder?: string;handleSelectedChange: (type: string, selected: string) => void;description?: string;disabled?: boolean;type: string;}
export default function DropDownCommon({label,list,selected,dropDownPlaceHolder,handleSelectedChange,description,disabled = false,type,}: DropDownProps): JSX.Element {const [isActive, setIsActive] = useState(false);
const toggleDropdown = (): void => {if (!disabled) {setIsActive(!isActive);}};
const handleSelect = (type: string, item: string): void => {handleSelectedChange(type, item);setIsActive(false);};
return (<div className="container">{label && (<label className={`dropdown-label ${disabled ? "disabled" : ""}`}>{label}</label>)}<div className="dropdown-container"><divclassName={`dropdown-body ${isActive ? "active" : ""} ${disabled ? "disabled" : ""}`}onClick={toggleDropdown}><div className={`dropdown-selected ${disabled ? "disabled" : ""}`}>{selected || dropDownPlaceHolder || "Select an item"}</div><div className={`dropdown-selected ${disabled ? "" : "active"}`}>{isActive ? "▲" : "▼"}</div></div>
<div className={`dropdown-menu-container ${isActive ? "active" : ""}`}>{list.map((item) => (<divkey={item}className={`dropdown-item-container ${item === selected ? "selected" : ""}`}onClick={(): void => {handleSelect(type, item);}}>{item}</div>))}</div></div>{description && <div className="description">{description}</div>}</div>);}2. style 지정
/* 드롭다운 */.dropdown-label {margin-bottom: 8px;font-size: 16px;font-weight: 700;color: #333;}
.dropdown-label.disabled {color: #777;}
.dropdown-container {position: relative;}
.dropdown-container:hover {cursor: pointer;}
.dropdown-body {display: flex;justify-content: space-between;align-items: center;width: 300px;height: 50px;background-color: #fff;border: 1px solid #ccc;cursor: pointer;border-radius: 8px;}
.dropdown-body.active {background-color: #fff;border: 1px solid #666;}
.dropdown-selected {font-size: 16px;padding: 14px 16px;}
.dropdown-selected.disabled {color: #777;}
.dropdown-menu-container {position: absolute;top: calc(100% + 8px);left: 0;z-index: 1;width: 300px;max-height: 200px;overflow-y: auto;background-color: #fff;border: 1px solid #666;border-radius: 8px;box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1);display: none;}
.dropdown-menu-container.active {display: block;}
.dropdown-item-container {padding: 16px;font-size: 16px;color: #333;cursor: pointer;}
.dropdown-item-container:hover {background-color: #f0f0f0;}
.dropdown-item-container.selected {background-color: #f0f0f0;}
.description {height: 17px;font-size: 12px;color: #333;margin: 8px 0px;}3. 컴포넌트 사용
<DropDownCommonlabel={"직군"}list={roleArr}selected={role}dropDownPlaceHolder={roleArr[0]}handleSelectedChange={(item) => handleSelectedChange("role", item)}type={"role"}/>'React > 과제 테스트' 카테고리의 다른 글
[체크리스트] 상태관리 (0) 2023.11.28 [체크리스트] 모듈화 (1) 2023.11.28 [인사정보] React url 절대 경로, url 전환, 카드 뒤집기, 로컬스토리지, 스크롤 동작 (0) 2023.08.09 [Input 이벤트] input readonly, 백스페이스 기능 (0) 2023.08.08 [Input 이벤트] 포커스 이벤트, 영역 외부 클릭시 상태 변화, document.addEventListener (0) 2023.08.08 - typeof : 객체 데이터를 객체 타입으로 변환해주는 연산자