state
state는 컴포넌트가 가질 수 있는 상태이다.
useState는 컴포넌트의 상태를 간편하게 생성하고 업데이트시킬 수 있는 도구를 제공해 준다.
const [state, setState] = useState(초기값);
state : 현재 상태 값
setState : state를 변경시켜 주고 싶을때 함수를 이용해서 간편하게 변경시켜줄 수 있다.
state를 직접 변경하면 안 되는 이유
state의 변경 전과 후의 메모리 주소 비교를 통해 state의 변경을 확인하고 렌더링을 하게 되는데 state를 바로 수정하면 값은 바뀌지만 메모리 주소는 변함없기 때문에 렌더링을 하지 않는다.
현재 state와 setState를 비교하여 값이 다를 때 render 함수를 호출한다. 그래서 state를 바로 수정하면 render 함수를 호출하지 않아서 state 변경이 일어나도 렌더링이 일어나지 않는다.
따라서 React에서 컴포넌트 state는 불변성을 지키는 것이 중요하다.
사용방법
const [count, setCount] = useState(0);
초기 count값이 0인데 이 값을 바꾸려면 setCount(6); 으로 count를 0에서 6으로 바꿀 수 있다.
setState 값을 사용해서 state를 변경하면 해당 컴포넌트는 화면에 다시 렌더링 된다.
예시
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
console.log("업데이트");
return (
<div>
<span>누른 횟수 : {count}번</span>
<br />
<button onClick={handleClick}>count</button>
</div>
);
}
export default App;
실행결과
useState를 사용해서 state값이 변경이 될 때마다 화면이 렌더링이 되는지 확인하기 위해서 업데이트를 콘솔 출력에 나오게 하고 돌려봤더니 처음 렌더링 할 때 1번 나왔고 6번 카운트된 만큼 업데이트가 출력된 것을 확인할 수 있었다.
state가 여러 개일 때
아래의 코드처럼 입력하는 값이 여러 개 일 때 하나하나 state를 만들어서 onChange 함수까지 개별로 만들면 코드가 굉장히 길어지고 귀찮다.
import { useState } from "react";
function App() {
const [title, setTittle] = useState("");
const [name, setName] = useState("");
const [location, setLocation] = useState("");
const [tag, setTag] = useState("");
const titleChange = (e) => {
setTittle(e.target.value);
};
const nameChange = (e) => {
setName(e.target.value);
};
const locationChange = (e) => {
setLocation(e.target.value);
};
const tagChange = (e) => {
setTag(e.target.value);
};
console.log("업데이트");
return (
<div>
<div>
<span>React_Hooks_Test</span>
<br />
<span>title : </span>
<input onChange={titleChange} value={title} />
<br />
<span>name : </span>
<input onChange={nameChange} value={name} />
<br />
<span>location : </span>
<input onChange={locationChange} value={location} />
<br />
<span>tag : </span>
<input onChange={tagChange} value={tag} />
</div>
<br />
<br />
<div style={{border:'1px solid #000000'}}>
<span>결과</span>
<br />
<span>title : {title} </span>
<br />
<span>name : {name} </span>
<br />
<span>location : {location} </span>
<br />
<span>tag : {tag} </span>
<br />
</div>
</div>
);
}
export default App;
결과
따라서 이런 경우에는 useState를 하나로 여러 개의 state를 관리할 수 있다.
import { useState } from "react";
function App() {
const [data,setData] = useState({
title:"",
author:"",
location:"",
tag:"",
});
const {title, author, location, tag} = data;
const handleChange = (e) =>{
setData({
...data,[e.target.name]:e.target.value,
});
};
console.log("업데이트");
return (
<div>
<div>
<span>React_Hooks_Test</span>
<br />
<span>title : </span>
<input name="title" onChange={handleChange} value={title} />
<br />
<span>author : </span>
<input name="author" onChange={handleChange} value={author} />
<br />
<span>location : </span>
<input name="location" onChange={handleChange} value={location} />
<br />
<span>tag : </span>
<input name="tag" onChange={handleChange} value={tag} />
</div>
<br />
<br />
<div style={{border:'1px solid #000000'}}>
<span>결과</span>
<br />
<span>title : {title} </span>
<br />
<span>author : {author} </span>
<br />
<span>location : {location} </span>
<br />
<span>tag : {tag} </span>
<br />
</div>
</div>
);
}
export default App;
코드 분석
const [data,setData] = useState({
title:"",
author:"",
location:"",
tag:"",
});
수정한 코드를 보면 하나의 useState에서 4개의 data를 관리한다.
const {title, author, location, tag} = data;
data 객체에서 title, author, location, tag 속성을 추출한다.
const handleChange = (e) =>{
setData({
...data,[e.target.name]:e.target.value,
});
};
input에서 변경이 있을 때 호출되는 함수이다.
...data는 스프레드 연산자(...)를 사용하여 data 객체의 모든 속성을 새로운 객체에 복사하는 것을 의미한다.
그다음 [e.target.name]: e.target.value 부분으로 특정 속성의 값을 변경한다.
즉, state는 불변성을 지키는 것이 중요하기 때문에 data 객체를 직접 수정하지 않고 새로운 객체를 만들어서 setData 함수를 통해 상태를 업데이트한다.
결과