첫화면에 api로 요청한 데이터를 그려줘야함
useEffect에서 데이터의 응답은 확인되나, State에 담기지 않는 상황
sate를 업데이트 하기 위해 의존성 배열에 변수를 추가했으나
api 의 무한호출 발생 🚨
const [isPractice, setIsPractice] = useState<>([])
useEffect(() => {
settingData()
}, [isPractice])
const settingData = async () => {
const res = await getPractice(idx)
if (res === false) {
return
}
setIsPractice(res)
}
state의 상태가 변하면, settingData()가 호출되고 isPractice의 상태가 변경된다.
isPractice은 동적인 값이므로, 값이 셋팅된 이후로는 업데이트 되지않고
따라서 useEffect의 동작 또한 멈출꺼라고 생각했다.
🤔 state의 값이 달라지지 않았는데, 왜 useEffect가 재실행되는 것인가 ?
useEffect는 의존성 배열에 포함된 값이 변화할때 실행됨
- 가설1 - 의존성 배열에 작성된 state의 값을 비교하지 않는걸까 ?
- 가설2 - 비동기 함수로 인한 타이밍의 문제일까 ?
useEffect를 하나더 추가 후, 의존성 배열을 분리
1번 Hook으로 첫화면에 데이터를 그려주고
2번 Hook으로 state의 변화가 감지되면 화면을 새로 그려줄수 있도록 설정
아래 코드로 무한루프가 멈춤
const [isPractice, setIsPractice] = useState<practiceType[]>([])
//No.1
useEffect(() => {
settingData()
}, [])
//No.2
useEffect(() => {
}, [isPractice])
const settingData = async () => {
const res = await getPracticeSub(idx)
if (res === false) {
return
}
setIsPractice(res)
}
이 방법으로 무한루프가 해결됬다는 건, state의 값이 업데이트 되었을때만 useEffect가 재실행 된다는 것, 고로 useEffect는 state의 값을 비교하고 있다. *얕은 비교(shallow comparison)
비동기 함수였던 settingData()를 동기 함수로 바꾸어 보았다.
그리고 동기함수에서도 무한루프 멈추지 않았다.
useEffect 안에서 set 함수와 변수를 함께 사용했을때 무한 루프가 나타나는 것은
동기 / 비동기 함수 와는 관련이 없다는 점을 확인
const [isPractice, setIsPractice] = useState<practiceType[]>([])
useEffect(() => {
settingData()
}, [isPractice])
const settingData = () => {
const res = getPractice(idx)
if (res === false) {
return
}
setIsPractice(res)
}
그렇다면 useEffect의 무한루프는 무엇으로 인해 발생하는 걸까 ?
① 문제코드에서 useEffect는 isPractice의 상태가 변경될때마다 다시 실행되도록 설정되어있다.
② isPractice 상태가 변경되면 React는 다시 상태 업데이트를 예약하고 useEffect를 실행한다.
③ 여기서 중요한 점은 업데이트 이전값과 이후의 값이이 동일하더라도,
React는 예약된 상태 업데이트가 완료 될때까지 useEffect를 실행한다.
④ 이로인해 계속해서 변수에 값이 할당되며 useEffect가 재실행되어 무한루프가 발생
//No.1
useEffect(() => {
console.log('[1번 실행]')
settingData()
}, [])
//No.2
useEffect(() => {
console.log('[2번 실행]', isPractice)
}, [isPractice])
첫번째 Hook은 컴포넌트가 마운트될때 한번만 실행되며,
두번째 Hook은 isPractice의 상태가 변경될때마다 실행됨
두개의 Hook은 분리 되어있기때문에 isPractice가 업데이트 됬다고해서
첫번째 Hook이 다시 호출되지 않음
LOG [1번 실행] // settingData () 실행
LOG [2번 실행] [] //상태 업데이트 예약
LOG [2번 실행] [{"idx": 3,"profileName": "소소한 일상을 보내는", "profileSubName": "개발자"}]
// isPractice 에 데이터 담김
LOG에서 isPractice의 데이터가 세번째에서야 담긴 이유는, state가 데이터를 비동기로 처리되기 때문이다.
settingData()는 첫번째 로그 이후 실행되지만, isPractice는 바로 업데이트 되지 않는데,
위에서 다뤘던 업데이트를 예약과 반영사이에 시간차이가 발생한다.
이를, 상태 업데이트의 비동기적 특성이라고 이야기하며
이 부분을 이해하면 React 컴포넌트의 생명주기와 상태 관리를 더 효과적으로 다룰 수 있다. . !