§1_ spread 문법 + 객체로 여러 useState 변수들을 간결화 정리
● 예시 : Register.js 코드 변경 전,
function Register() {
const currentDate = formatDate(new Date());
const [name, setName] = useState("이름");
const [birth, setBirth] = useState(currentDate);
const [country, setCountry] = useState();
const [introduce, setIntroduce] = useState("");
const onChangeNameInput = (event) => {
setName(event.target.value);
};
const onChengeBirthInput = (event) => {
setBirth(event.target.value);
};
const onCountrySelect = (event) => {
setCountry(event.target.value);
};
const onChangeIntroduce = (event) => {
setIntroduce(event.target.value);
};
return(...);
}
Register.js 코드 변경 후,
import { useState } from "react";
function Register() {
const currentDate = formatDate(new Date());
//하나의 state 변수 input + useState({}) 객체로 초기화
const [input, setInput] = useState({
name: "",
birth: currentDate,
country: "",
Introduce: "",
});
const onChangeNameInput = (event) => {
setInput({
...input,//spread 문법으로, 기존 속성값 유지
name: event.target.value,//바꾸고 싶은 프로퍼티만 event.target.value 값 저장
});
};
const onChengeBirthInput = (event) => {
setInput({
...input,
birth: event.target.value,
});
};
const onCountrySelect = (event) => {
setInput({
...input,
country: event.target.value,
});
};
const onChangeIntroduce = (event) => {
setInput({
...input,
introduce: event.target.value,
});
};
return (
<>
);
}
export default Register;
§★2_ 각 useState를 변경해주는 이벤트 핸들러 하나로 통합하기
- 순서1_ 각 onChange를 담당하는 form 태그의 name속성에 useState의 변수이름과 동일하게 추가 설정
- 순서2_ 하나의 핸들러로 통일 + setState({...useState 객체 ,[event.target.name] : event.target.value})
- 순서3_ 모든 form 태그의 onChange 속성값을 onChange 핸들러로 통일
import { useState } from "react";
function formatDate(date) {
const YYYY = String(date.getUTCFullYear());
const MM = String(date.getUTCMonth() + 1).padStart(2, "0");
const DD = String(date.getUTCDate()).padStart(2, "0");
return `${YYYY}.${MM}.${DD}`;
}
function Register() {
const currentDate = formatDate(new Date());
const [input, setInput] = useState({
name: "",
birth: currentDate,
country: "",
Introduce: "",
});
const onChange = (event) => {
setInput({
...input,
[event.target.name]: event.target.value,//순서1
});
};
return (
<>
<div>
<input
name="name"//순서2
value={input.name}
onChange={onChange}//순서3
placeholder={"이름"}
/>
<h3>{input.name}</h3>
</div>
<div>
<input
name="birth"
type="date"
value={input.birth}
onChange={onChange}
placeholder={new Date()}
/>
<h3>{input.birth}</h3>
</div>
<div>
<select name="country" value={input.country} onChange={onChange}>
<option></option>
<option value="kr">한국</option>
<option value="un">미국</option>
<option value="ut">영국</option>
</select>
<h3>{input.country}</h3>
</div>
<div>
<textarea
name="introduce"
value={input.introduce}
onChange={onChange}
/>
<p>{input.introduce}</p>
</div>
</>
);
}
export default Register;
§3_ useRef
알아야 할 개념 :
Test.js
import { useRef } from "react";
export function Test() {
const refObj = useRef(0);
console.log(`재랜더링 :${refObj.current}`); //출력1
const onClickRefCuurentPlus = () => {
refObj.current++;
console.log(`핸들러 : ${refObj.current}`);//출력2
};
return (
<>
<button onClick={onClickRefCuurentPlus}>ref.current+1</button>
</>
);
}
각 출력위치에 대해서 알 필요가 있다.
- 출력1 : 랜더링 할때 출력되는 출력 위치
- 출력2 : 버튼을 클릭할때마다 출력되는 출력 위치
위의 내용을 통해 알 수 있는것 : useRef는 useState가 변할때, 랜더링되는 특성을 갖고있지 않다.
§2_ useRef의 객체를 이용해, 특정요소에 작동을 했을 시, event.target요소 외 다른 요소들에 대한 조건들 check하기 => useRef 객체 이용 :
예시 : 회원가입 페이지에서 '제출'버튼을 누를 시, 다른 input 요소 value가 비어있다면, 제출X => 그 해당 태그에 focus되도록 하기
- 순서1_ 컴포넌트에 inputRef의 useRef 객체 초기화
- 순서2 :제출 전 검사할 요소들에 ref속성에 useRef 객체 삽입
- 순서3_ 핸들러에서 검사할 내용 구현
- Register.js
import { useRef, useState } from "react";
function formatDate(date) {
const YYYY = String(date.getUTCFullYear());
const MM = String(date.getUTCMonth() + 1).padStart(2, "0");
const DD = String(date.getUTCDate()).padStart(2, "0");
return `${YYYY}.${MM}.${DD}`;
}
function Register() {
const currentDate = formatDate(new Date());
const inputRef = useRef();
const [input, setInput] = useState({
name: "",
birth: currentDate,
country: "",
Introduce: "",
});
const onChange = (event) => {
setInput({
...input,
[event.target.name]: event.target.value,
});
};
const onSubmit = () => {
if (input.name === "") {
inputRef.current.focus();
}
};
return (
<>
<div>
<input
ref={inputRef}
name="name"
value={input.name}
onChange={onChange}
placeholder={"이름"}
/>
<h3>{input.name}</h3>
</div>
<div>
<input
name="birth"
type="date"
value={input.birth}
onChange={onChange}
placeholder={new Date()}
/>
<h3>{input.birth}</h3>
</div>
<div>
<select name="country" value={input.country} onChange={onChange}>
<option></option>
<option value="kr">한국</option>
<option value="un">미국</option>
<option value="ut">영국</option>
</select>
<h3>{input.country}</h3>
</div>
<div>
<textarea
name="introduce"
value={input.introduce}
onChange={onChange}
/>
<p>{input.introduce}</p>
</div>
<div>
<button onClick={onSubmit}>제출</button>
</div>
</>
);
}
export default Register;
§3_ useRef vs let 변수
예시코드1 :
import { useRef, useState } from "react";
let outVar = 0;
export function Test() {
const exampleRef = useRef(0);
const [useCnt, setUseCnt] = useState(0);
let inVar = 0;
const onClickBtn = () => {
/*
setUseCnt(useCnt +1);
*/
exampleRef.current++;
inVar++;
outVar++;
console.log(`ref.current : ${exampleRef.current}`);
console.log(`outVar : ${outVar}`);
console.log(`inVar : ${inVar}`);
};
return (
<>
<button onClick={onClickBtn}>+</button>
</>
);
}
의미 :
상태는 렌더링을 딱 한번만 한 상태라 버튼을 누를 시에만 Ref, inVar, outVar이 증가한다.
예시코드2 :
import { useRef, useState } from "react";
let outVar = 0;
export function Test() {
const exampleRef = useRef(0);
const [useCnt, setUseCnt] = useState(0);
let inVar = 0;
const onClickBtn = () => {
setUseCnt(useCnt + 1);//state변수인, useCnt가 변하기에 , 버튼을 누를 시, 재랜더링 된다.
exampleRef.current++;
inVar++;
outVar++;
console.log(`ref.current : ${exampleRef.current}`);
console.log(`outVar : ${outVar}`);
console.log(`inVar : ${inVar}`);
};
return (
<>
<button onClick={onClickBtn}>+</button>
</>
);
}
의미 :
버튼을 누를 때마다, 재렌더링이 되는 데, 이때 컴포넌트 inVar은 0으로 다시 초기화 되면서, 증가하므로, inVar은 1로 유지, 나머지 변수들은 증가한다.
예시코드3 :
- App.js
import "./App.css";
import { Test } from "./components/Test";
function App() {
return (
<div>
<div>
<Test />//Test 컴포넌트 1
</div>
<div>
<Test />//Test 컴포넌트 2
</div>
</div>
);
}
export default App;
- Test.js 는 그대로,
의미 :
OutVar과 useRef를 제대로 보여주는 출력결과이다.
결론 : useRef는 렌더링 되는 컴포넌트 1개당 하나의 고유 객체 변수 역할을 할 수 있는 독특한 새끼임
'팀프로젝트_기록일지 > React_이정환_useState,useRef' 카테고리의 다른 글
(6).이정환_react.js강의_ React's LifeCycle과 역할, LifeCycle_Control방=>useEffect (0) | 2025.01.15 |
---|---|
(5).이정환_react.js강의_ 프로젝트_실습1_카운터프로그램 만들기 (0) | 2025.01.15 |
(4).이정환_react.js강의_ React의 Hook의 정의, 규칙, 커스텀 훅 만들기 (0) | 2025.01.14 |
(2).이정환_react.js강의_ 이벤트 핸들링에서 이벤트 객체 , 합성이벤트객체(작성중) (0) | 2025.01.13 |
(1).이정환_react.js강의_ 컴포넌트 (0) | 2025.01.13 |