Hooks
- 리액트 '함수형 컴포넌트' 에서 사용할 수 있는 기능
useState
- React에서 제공하는 Hook 중 하나
- 함수형 컴포넌트 내에서 상태를 관리 하는 기능
- 호출 시 변화되는 상태값과 해당 상태값을 업데이트 하는 함수를 제공
- 호출 시 상태 업데이트 함수는 비동기적 처리가 기본으로 진행
- 상태 변경 시 컴포넌트의 재 렌더링을 유발
기본 구문
const [state, setState] = useState<type>(initialValue);
- state: 현재의 상태값(변수)
- setState: 상태를 업데이트 하는 함수
- initialValue: 상태의 초기값
더보기
const [count, setCount] = useState<number>(0);
const handelUpclick = () => {
// 1) 상태 설정 함수를 그대로 사용
// >> 이전의 상태를 직접 참조
// ! 주로 현재(이전) 값과 관련없는 변화가 이루어질 경우 사용!
// setCount(count + 1) // 0 + 1
// setCount(count + 1) // 0 + 1
// 2) 함수형 업데이트를 사용
// >> 이전 상태 값을 기반으로 상태를 업데이트 하는 경우 (권장)
setCount(prevCount => prevCount + 1); // 0 + 1
setCount(prevCount => prevCount + 1); // 1 + 1
setCount(prevCount => prevCount + 1); // 2 + 1
}
const handleDownClick = () => {
setCount(prevCount => prevCount - 1);
}
const handleDownClick = () => {
setCount(prevCount => prevCount - 1);
}
(예시 코드)
더보기
export default function UseState03() {
//# 클릭 이벤트 핸들러
const [count, setCount] = useState<number>(0);
const handleIncrementButton = (e: React.MouseEvent<HTMLButtonElement>) => {
setCount(prevcount => prevcount + 1);
console.log(e.target);
};
//# 입력 이벤트 핸들러
const [input, setInput] = useState<string>('');
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setInput(e.target.value);
console.log(e.target);
};
//# 키보드 이벤트 핸들러
// >> 'Enter' 키 클릭에 대한 반응을 처리
const [enter, setEnter] = useState<string>('');
const handleKeyboard = (e: React.KeyboardEvent<HTMLInputElement>) => {
console.log(e.key);
if(e.key === 'Enter'){
console.log('Enter 키가 눌려졌습니다.');
// 입력된 내용을 배열의 요소에 추가
// , 다양한 로직 활용
setEnter(e.currentTarget.value);
}
};
(회원가입 구현)
더보기
import React, { useState } from "react";
/*
! useState를 사용한 이벤트 처리 & 상태 관리
? 요구 사항 정리
1. 폼 필드
: 사용자 아이디, 비밀번호, 이메일 주소 입력 (문자열 데이터)
2. 입력 유효성 검사
: 모든 필드 입력창은 비워져 있을 수 X
3. 상태 관리
: 입력값은 객체로 하나의 useState를 통해 관리 (formData)
4. 폼 제출
: 폼 제출 시 모든 입력 값이 콘솔에 출력 (객체 자체를 출력)
>> 입력 조건을 만족하지 않는 경우(유효성 검사 불일치 시) - 오류 메시지 출력
>> 오류 메시지 관리도 컴포넌트 내에서 상태 관리
*/
/*
! 작업 순서
- 폼과 필요한 입력 필드 생성
- 입력 필드에 대한 상태 로직 관리 (onChange)
- 입력 유효성 검사 추가, 오류 메시지 표시 로직 작성
- 폼 제출 함수 구현, 콘솔에 입력 데이터 출력
*/
interface IformData {
id: string;
password: string;
email: string;
}
export default function UseState04() {
//! 폼 데이터 상태 관리
const [formData, setFromData] = useState<IformData>({
id: "",
password: "",
email: "",
});
//! 폼 입력 오류 메시지 상태 관리
const [errors, setErrors] = useState<IformData>({
id: "",
password: "",
email: "",
});
//! 각 입력 필드 변수 선언 (비구조화 할당)
const { id, password, email } = formData;
//! 폼 제출 이벤트를 처리하는 이벤트 핸들러
const handleSignUpSubmit = (e: React.FormEvent) => {
//? 폼 제출에 대한 기본 동작을 방지
e.preventDefault();
//? 임시 오류 메시지 객체 생성
// >> 아이디, 비밀번호, 이메일 순으로 오류 메시지를 담아두는 객체
// >> 최종 유효성 검사가 끝나면 해당 객체를 setErrors에 전달
let tempErrors = {
id: "",
password: "",
email: "",
};
//? 폼의 유효성 상태를 추적하는 변수
// : boolean 타입의 변수
// >> 하나라도 유효하지 않으면 false로 지정
let isValid = true;
// == 아이디 유효성 검사 ==
if (!id) {
// 아이디 입력 필드가 비워져 있으면
tempErrors.id = "아이디를 입력해주세요."; // 오류 메시지 설정
isValid = false;
}
// == 비밀번호 유효성 검사 ==
if (!password) {
// 비밀번호 입력 필드가 비워져 있으면
tempErrors.password = "비밀번호를 입력해주세요."; // 오류 메시지 설정
isValid = false;
}
// == 이메일 유효성 검사 ==
if (!email) {
// 이메일 입력 필드가 비워져 있으면
tempErrors.email = "이메일를 입력해주세요."; // 오류 메시지 설정
isValid = false;
}
//? 오류 상태를 업데이트
setErrors(tempErrors);
//? 모든 입력이 유효한 경우
// >> 콘솔에 내용 출력
// >> 입력 필드 초기화
if (isValid) {
console.log("회원 가입 데이터: ", formData);
alert(`회원가입을 축하합니다 ${id}님`);
// 데이터 활용 후 필드 초기화
setFromData({
id: "",
password: "",
email: "",
});
}
};
//! 입력 필드의 변경을 감지하는 이벤트 핸들러
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// 이벤트 객체에서 입력 필드의 이름과 값을 추출
const { name, value } = e.target;
setFromData({
// 기존 폼 데이터의 값을 복사 (스프레드 연산자)
...formData,
// 변경된 필드의 값을 업데이트
[name]: value
});
};
return (
<div
style={{
margin: "20px",
padding: "20px",
border: "1px solid #ddd",
textAlign: "center",
}}
>
<h3>회원가입 구현</h3>
<form onSubmit={handleSignUpSubmit}>
<div>
<label>
아이디:
<input
type="text"
name="id"
value={id}
onChange={handleInputChange}
/>
</label>
{/* {errors.id && <p style={{ color: "red" }}>{errors.id}</p>} */}
</div>
<div>
<label>
비밀번호:
<input
type="text"
name="password"
value={password}
onChange={handleInputChange}
/>
</label>
{/* {errors.password && <p style={{ color: "red" }}>{errors.password}</p>} */}
</div>
<div>
<label>
이메일:
<input
type="text"
name="email"
value={email}
onChange={handleInputChange}
/>
</label>
{/* {errors.email && <p style={{ color: "red" }}>{errors.email}</p>} */}
{errors.id ? (
<p style={{ color: "red" }}>{errors.id}</p>
) : errors.password ? (
<p style={{ color: "red" }}>{errors.password}</p>
) : (
<p style={{ color: "red" }}>{errors.email}</p>
)}
</div>
<button type="submit">회원가입</button>
</form>
</div>
);
}
useState를 사용한 다양한 타입 상태 관리
더보기
interface IUser {
id: number;
name: string;
}
export default function UseState05() {
const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>("");
const [isVisiable, setIsVisiable] = useState<boolean>(false);
const [user, setUser] = useState<IUser>({
id: 0,
name: "",
});
// 배열의 경우 초기값에 주로 [] 빈 배열 설정
const [items, setItems] = useState<string[]>([]);
const handleUserChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setUser({
...user,
[name]: value,
});
}
const addItem = () => {
const newItem = `Item ${items.length + 1}`;
setItems([...items, newItem]);
}
;
return (
<div
style={{
margin: "20px",
border: "1px solid blue",
padding: "20px",
}}
>
<h5>여러 타입의 상태 관리</h5>
{/* 숫자형: 카운터 증가 버튼 */}
<p>count: {count}</p>
<button
onClick={() => {
setCount((prevcount) => prevcount + 1);
}}
>
증가
</button>
{/* 문자열: 사용자 이름 입력 필드 */}
<p>Name: {name}</p>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
{/* 논리형: 토글 버튼 */}
<p>Visiable? : {isVisiable ? "yes" : "no"}</p>
<button onClick={() => setIsVisiable(!isVisiable)}>토글 버튼</button>
{/* 객체: 사용자 정보 수정 입력 필드 */}
{/*
객체의 속성 데이터는 HTML 영역 내에 출력 가능
>> 객체 구조 자체는 출력 불가
>> 객체를 문자열 형식(JSON 형식으로 변환 후)으로 출력
*/}
<p>
User: {user.id} {user.name}
</p>
<p>User2: {JSON.stringify(user)}</p>
<input
type="text"
name="name"
value={user.name}
placeholder="사용자 이름"
onChange={handleUserChange}
/>
<input
type="number"
name="id"
value={user.id}
placeholder="사용자 아이디"
onChange={handleUserChange}
/>
{/* 배열: 배열 요소 추가 */}
<p>Items: {items}</p>
<button onClick={addItem}>아이템 추가</button>
</div>
);
}
컴포넌트 트리 안에서의 상태
- 상태를 컴포넌트 트리의 아래로 전달
- 부모에서 자식 컴포넌트로 상태 전달
상태(State) VS 속성(Props)
1) 상태
- 컴포넌트 내부에서 관리되는 데이터
- 상태가 변겨오디면 렌더링을 유발(업데이트)
- 컴포넌트가 자기 자신의 상태 변경 가능
2) 속성
- 부모 컴포넌트(외부)로 부터 받은 데이터
- 컴포넌트 간의 데이터 전달에 사용
- 읽기전용 데이터: 자식 컴포넌트에서 수정 불가
더보기
type UserType = {
username: string;
height: number;
};
const initialValue: UserType = {
username: "홍동현",
height: 181,
};
export default function UseState06() {
const [userInfo, setUserInfo] = useState<UserType>(initialValue);
// 자식 컴포넌트에게 전달할 데이터 관리
const [submittedData, setSubmittedData] = useState<UserType | undefined>(initialValue);
const { username, height } = userInfo;
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setUserInfo({
...userInfo,
[name]: value,
});
};
const handleSubmit = () => {
// 자식 컴포넌트에 데이터 전달
setSubmittedData(userInfo)
}
return (
<div>
<input
type="text"
placeholder="이름"
name="username"
value={username}
onChange={handleInputChange}
/>
<input
type="text"
placeholder="키"
name="height"
value={height}
onChange={handleInputChange}
/>
<button onClick={handleSubmit}>확인</button>
<ChildComponent userData={submittedData}/>
</div>
);
}
'React' 카테고리의 다른 글
[React] Hooks - useEffect (0) | 2024.08.31 |
---|---|
[React] Hooks - useRef (0) | 2024.08.31 |
[React] Handler (0) | 2024.08.29 |
[React] Rendering (0) | 2024.08.29 |
[React] Props (0) | 2024.08.29 |