1.useState가 필요한 이유
function App() {
let content = 'init content'
function handleSelect(){
content = 'update content'
}
return {
<div>
<p>{content}</p>
<button onClick={handleSelect}>
</div>
}
}
1).잘못된 구현 : content의 값이 화면에서 업데이트 되지 않음. 즉 return()내의 jsx 코드가 한번만 실행되어 UI가 업데이트 되지 않음 > 모든 JSX코드가 재평가되지 않음
2). 값이 업데이트 되지 않는 이유 : 리액트는 JSX 코드를 보고 현재 렌더링된 UI와 비교하기 때문에 UI를 업데이트 하려면 리액트에 의해 재평가 되어야 함.
3). 해결방안 : useState();
(1). 리액트 라이브러리에서 불러와야하는 특별한 함수의 도움을 받음
(2). 리액트에게 데이터가 변한것을 알려주고 리액트가 UI를 업데이트하는 리액트의 Hooks
*Hooks 함수는 컴포넌트 함수 안에서 바로 호출 되어야 하고 내부 함수 안에서 중첩되면 안됨 , 컴포넌트 함수의 최상위에서 호출되어야 함
import {useState} from 'react';
function App() {
const [content, setContent] = useState('init content');
function handleSelect(){
setContent('update content')
console.log(content)
}
return {
<div>
<p>{content}</p>
<button onClick={handleSelect}>
</div>
}
}
(3). 코드 설명
content - 현재 상태값
setContent - 상태값 업데이트 함수
useState('init content') - 초기 상태값
const를 사용하는 이유 : 값이 바뀌게 되면 리액트가 값을 저장하고 컴포넌트가 리렌더링 되면서 상수에 값이 전달 됨. 그렇기 때문에 값을 바꿀 이유가 없음.
코드 실행 과정 : 사용자가 버튼을 클릭 > handleSelect가 실행됨 > setContent를 통해 리액트는 상태 업데이트의 스케줄을 조정함 > console.log(content)에는 아직 값이 바뀌지 않은 'init content'가 찍힘 > handleSelect함수가 끝남 > 리액트가 값을 업데이트하고 컴포넌트를 리렌더링 함 > content 값은 'update content'로 변경됨
(4). setContent(content + 'update') 와 setContent((prev) => prev + 'update')는 뭐가 다를까
setContent(content + 'update')
import {useState} from 'react';
function App() {
const [content, setContent] = useState('init content');
function handleSelect(){
setContent(content + ' update'); //'init content update'로 상태값 변경 스케쥴 예약
setContent(content + ' update'); //'init content update'로 상태값 변경 스케쥴 예약
}
return {
<div>
<p>{content}</p>
<button onClick={handleSelect}>
</div>
}
}
=> 위의 경우에는 <p>태그 내에 "init content update"가 나올것이다. setContent코드를 두번 쓰긴 했지만 저 코드의 의미는 content+ ' update'로 content상태값을 변경하는 스케줄예약을 두번 하는 것이다. 말그대로 예약이므로 content는 handleSelect내에서 변경되는것이 아니다. 즉 두번째 setContent가 실행될 때에도 content는 그대로 'init content'상태이기 때문에. 결과적으로 init content update가 찍히게 된다.
setContent((prev) => prev + 'update')
import {useState} from 'react';
function App() {
const [content, setContent] = useState('init content');
function handleSelect(){
setContent((prev) => prev + ' update') // 'init content update'로 상태값 변경 예약
setContent((prev) => prev + 'update') // 'init content update update'로 상태값 변경 예약
}
return {
<div>
<p>{content}</p>
<button onClick={handleSelect}>
</div>
}
}
=> 위의 경우에는 예정된 업데이트가 실행될 시점의 최신 상태값을 받음
태그 내에 "init content update update"가 나올것이다.함수식으로 사용하게 되면 실시간으로 최신값을 가져올 수 있다. setContent 내에 받아오는 prev 라는 매개변수는 가장 최신의 상태값을 가져오게 된다. 첫번째로 setContent를 쓰게 될 때 init content update로 바꿨고 두번째로 사용될 때는 리액트가 가장 최신 버전의 상태값을 가져오기 때문에 가장 최신의 상태값인 init content update + update가 되는것이다.
(5). 만약 상태값이 배열이나 객체인 경우
잘못된 접근
const [array, setArray] = useState([]);
function updateArray(idx,newVal){
setArray((prev) => {
prev[idx] = newVal;
return prev;
})
}
=> 배열이나 객체는 참조값이라서 메모리에 보관됨. 메모리 속의 기존값을 바로 변경하게 됨 => 리액트가 실행하는 예정된 상태 업데이트 보다 이전에 일어남
올바른 접근
const [array, setArray] = useState([]);
function updateArray(idx,newVal){
setArray((prev) => {
let newArray = [...prev]
newArray[idx] =newVal;
return newArray;
})
}
=> 복사값을 만들어 업데이트 후 복사값 리턴
2. 상태값 배칭
1). 같은 state 업데이트가 여러번 있을 때 여러번 렌더링되지 않음 > 한번의 컴포넌트 함수 실행 유도
'React' 카테고리의 다른 글
[React] proxy props 사용하기 (0) | 2024.04.02 |
---|---|
[React] key prop의 중요성 (1) | 2024.03.29 |
[React] 동적인 eventHandler 구현 시 주의 (0) | 2024.03.29 |
[React] 컴포넌트, index.html, index.jsx, jsx 특징, React 실행방식 (0) | 2024.03.28 |
[React] React에 대한 짧은 개요 (0) | 2024.03.27 |