[React] useState
React에서 함수형 컴포넌트로 개발 한다면 React Hooks이라는 매우 편리한 기능을 사용 할 수 있습니다.
이번에는 React Hooks 중에서도 가장 기본적인 useState에 대해 정리 해보겠습니다.
[ 개념]
React에서 state라는 건 무엇일까요?
state란 컴포넌트가 가질 수 있는 상태를 의미합니다.
예를 들어 Watch라는 컴포넌트가 있다면 state로는 time을 가지고 있을 것입니다.
useState는 컴포넌트의 상태를 간편하게 생성하고, 업데이트 할 수 있는 도구를 제공 해줍니다.
state에 생성과 동시에 가져야 하는 초기값을 useState 함수의 인자로 넣어주면
state와 setState라는 두 가지 요소를 배열 형태로 return 해줍니다. (초기값이 없으면 null로 설정 됩니다.)
현재 상태값은 state에 담겨 있고, state를 변경 하고 싶을 때는 setState 함수를 이용해서 간편하게 변경 해줄 수 있습니다.
(state와 setState의 이름은 원하는 대로 지정 해줄 수 있습니다.)
예시를 들어 설명 해보겠습니다.
이 Watch 컴포넌트 안에는 time이라는 state가 생성 되었고 초기값을 5입니다.
값을 변경 해주고 싶을 때는 setTime 함수에 인자에 변경하고 싶은 값을 넣어주면 됩니다.
setState 함수를 사용하여 값을 변경하면 해당 컴포넌트를 화면에 다시 렌더링(리렌더링) 됩니다.
[ 실습 ]
초기값이 1시인 state를 생성하고 Update 버튼을 누를 때마다 1씩 증가하는 예제입니다.
import React, { useState } from "react";
import "./App.css";
function App() {
const [time, setTime] = useState(1);
const handleClick = () => {
setTime(time + 1);
};
console.log(time, "업데이트!")
return (
<div>
<span>현재 시간 : {time}</span>
<button onClick={handleClick}>Update</button>
</div>
);
}
export default App;
useState를 사용하여 초기값은 1로 지정하였고, jsx 문법에 따라 {} 안에 state를 넣어 주었습니다.
Update 버튼을 onClick 할 때마다 handleClick 함수가 실행 되면서 setTime에 time+1된 값을 넣어 주었고
예제를 보면 Update 버튼을 누를 때마다 컴포넌트가 리렌더링 되면서 시간이 변경 되는 것을 볼 수 있습니다!
이때 alphabet이라는 컴포넌트에 a, b, c라는 여러 개의 state가 있다는 가정 하에
a라는 state의 값이 변경 되면 alphabet이라는 컴포넌트가 리렌더링 됩니다.
이때 컴포넌트 안에 있는 변수나 함수는 초기화 되지만,
state 함수들은 초기화 되지 않습니다! (컴포넌트를 언마운트 하지 않는 이상)
→ useState로 업데이트 해준 값으로 유지됩니다. (업데이트 되지 않았다면 기존의 값을 유지합니다.)
현재 handleClick 함수는 누를 때마다 1씩 증가하기 때문에 시계스럽지 않습니다.
그렇다면 이번에는 조건문을 사용하여 시계스럽게 변경 해보겠습니다!
import React, { useState } from "react";
import "./App.css";
function App() {
const [time, setTime] = useState(1);
const handleClick = () => {
let newTime;
if (time >= 12) {
newTime = 1;
} else {
newTime = time + 1;
}
setTime(newTime);
};
console.log(time, "업데이트!");
return (
<div>
<span>현재 시간 : {time}</span>
<button onClick={handleClick}>Update</button>
</div>
);
}
export default App;
handleClick 함수 안에 newTime이라는 변수를 하나 선언하고, 조건문을 사용하여 time이 12 이상이면 newTime을 1로 변경하고, 아니라면 newTime에 time + 1을 수행하여 맨 마지막에는 setTime 함수의 인자로 newTime을 넣는 코드로 변경 하였습니다.
useState의 대한 전반적인 내용을 정리 해보았고, 이번에는 useState에 대해 더 깊게 알아 보겠습니다.
import React, { useState } from "react";
import "./App.css";
function App() {
const [names, setNames] = useState(["홍길동", "오새봄"]);
const [input, setInput] = useState("");
const handleInputChange = (e) => {
setInput(e.target.value);
};
const handleClick = () => {
const newNames = [...names, input];
setNames(newNames);
setInput("");
};
return (
<div>
<input type="text" value={input} onChange={handleInputChange}></input>
<button onClick={handleClick}>Upload</button>
{names.map((name, index) => {
return <p key={index}>{name}</p>;
})}
</div>
);
}
export default App;
또는 콜백 함수를 사용하여 추가 해줄 수도 있습니다.
(콜백 함수에 인자로 받은 prevState는 setNames 함수 안에 있는 names 값들을 의미합니다.)
const handleClick = () => {
setNames((prevState) => {
return [input, ...prevState];
});
setInput("");
};
useState에 초기값에 어떤 무거운 작업을 해야 한다면
useState 인자에 함수를 바로 넣으면 매번 리렌더링 될때마다 함수를 호출하기 때문에 그보다는
원하는 값을 리턴 해주는 콜백 형태을 넣어주면 처음 화면에 렌더링 될 때만 함수를 호출하기 때문에 훨씬 효율적이다!
비효율적인 예 (콜백 함수 사용 X)
효율적인 예 (콜백 함수 사용 O)