react 에서 State 는 컴포넌트의 상태를 말한다.
const [state, setState] = useState(초기값);
state 는 현재 상태값, setState 는 변경해주고 싶은 값이다.
예를 들어 시계라는 컴포넌트가 있다면, state 는 time 라고 볼 수 있는데
useState 는 이 상태를 업데이트 해주는 도구를 제공해준다!
import { useState } from "react";
function App() {
const [time, setTime] = useState(1);
return (
<div>
<span>현재 시각 : {time}시</span>
<button>Update</button>
</div>
);
}
export default App;
import { useState } from "react";
로 import 하고고
const [time, setTime] = useState(1);
로 useState를 사용했다.
지금 이 코드에서는 클릭했을 때 time + 1 을 해주고 싶음!
그래서 현재시각을 {time}함수로 만들어줬고
handleClick 함수를 만들어서 클릭했을 때 time+1 이 되게끔 했다.
function App() {
const [time, setTime] = useState(1);
const handleClick = () => {
let newTime;
if (time >= 12) {
newTime = 1;
} else {
newTime = time + 1;
}
setTime(newTime);
};
return (
<div>
<span>현재 시각 : {time}시</span>
<button onclick={hadleClick}>Update</button>
</div>
);
}
time 에는 업데이트 된 state 가 되는 것.
input 에 값을 넣으면 그 값이 저장되어 아래에 적히게끔 만들어 보자 .
우선 기본 코드는
import { useState } from "react";
function App() {
return (
<div>
<input type="text" />
<button>Upload</button>
</div>
);
}
export default App;
이제 이 코드에서 useState 를 사용해주기 위해
map 으로
를 return 해줄 것
map을 쓰기 위해서는 key 와 value 값이 있어야 한다.
{names.map((name, index) => {
return <p key={index}>{name}</p>;
})}
여기서 이제 input 안에 무슨 값이 있는지 트래킹해주는 state 함수가 있었으면 좋겠다!
빈 문자열을 초기값으로,
const [input, setInput] = useState('');
useState 를 생성해주고
input 값의 value 에 state 로 만들어줌!
이제 사용자가 input 값을 넣을 때
입력 할때마다 핸들링 할 수 있는 함수를 만들어 주자 !
const handleInputChange = (e) => {
setInput(e.target.value);
}
<input type="text" value={input} onChange={handleInputChange}/>
을 추가해주고 콘솔창으로 확인해보면
인풋값에 입력한대로 콘솔에 찍히고 있다!
자 이제 버튼을 클릭하면 상태를 업로드해주는 handleUpload 를 해주는 함수를 만들어 주자
const handleUpload = () => {
setNames(() => {
return()
})
}
handleUpload 에는 위에서 작성해준 setNames 를 불러옴!
setNames()안의 콜백의 인자에는 업데이트하기 이전 상태를 가지고 있게, return 안에 업데이트 할 상태를 출력하게 한다.
콜백 인자에는 prevState 넣어주면 되는데,
prevState 는 배열로 들어있기 때문에 return [input, ...prevState];
으로 작성해주면 된다.
const handleUpload = () => {
setNames((prevState) => {
console.log("이전 state:", prevState);
return [input, ...prevState];
});
};
콘솔로 지금 상태를 확인해보면 이렇게 이전의 state 가 잘 출력됨을 볼 수 있다.
지금까지의 코드를 보면
import { useState } from "react";
function App() {
const [names, setNames] = useState(["수콩", "콩콩"]);
const [input, setInput] = useState("");
const handleInputChange = (e) => {
setInput(e.target.value);
};
const handleUpload = () => {
setNames((prevState) => {
return [input, ...prevState];
});
};
return (
<div>
<input type="text" value={input} onChange={handleInputChange} />
<button onClick={handleUpload}>Upload</button>
{names.map((name, index) => {
return <p key={index}>{name}</p>;
})}
</div>
);
}
export default App;
근데 잠깐만요 !~!~!
지금 계속 이전의 값을 불러오는데 만약 이게 엄청 무거운 값이라면 성능이 너무 저하되는 것 아닌지..?
그래서
지금의 코드는 너무 비효율적이다!! 이걸 개선하기 위해서
const heavyWork = () => {
console.log("엄청 무거운 작업");
return ["수콩", "콩콩"];
};
한다고 생각하고! heavyWork 라는 함수를 만들어주자. 그러면 이걸 어떻게 쓰냐 ?
const [names, setNames] = useState(() => {
return heavyWork();
});
처음에 렌더링이 될때만 이 함수를 사용하고 싶기 때문에 초기값을 넣는 인자에 바로 값을 너어주는 것이 아니라, 콜백을 넣어준다!
그리고 콜백형태로 원하는 값(초기값)만을 리턴 해주는 것 .
이제 input 을 추가했을 때 '엄청 무거운 작업' 인 초기값이 안드는 것을 볼 수 있다!
결론적으로! 초기값을 넣어줄때 초기값이 무거운 작업이라면, 따로 함수를 만들어서 콜백을 통해 처음에만 렌더링 되게 해줄 수 있다 .
최종 코드
import { useState } from "react";
const heavyWork = () => {
console.log("엄청 무거운 작업");
return ["수콩", "콩콩"];
};
function App() {
const [names, setNames] = useState(() => {
return heavyWork();
});
const [input, setInput] = useState("");
const handleInputChange = (e) => {
setInput(e.target.value);
};
const handleUpload = () => {
setNames((prevState) => {
console.log("이전 state:", prevState);
return [input, ...prevState];
});
};
return (
<div>
<input type="text" value={input} onChange={handleInputChange} />
<button onClick={handleUpload}>Upload</button>
{names.map((name, index) => {
return <p key={index}>{name}</p>;
})}
</div>
);
}
export default App;