-
카테고리
-
세부 분야
프론트엔드
-
해결 여부
해결됨
이번강의 코드의 동작결과를 바탕으로 예측한 동작순서가 맞는지 알고싶습니다.
22.04.14 12:11 작성 조회수 149
0
이번 강의를 보고 코드를 정리한 후 실행결과를 확인했습니다.
콘솔이 생각했던것 보다 7라인 더 찍혀서 궁금해서 질문 남깁니다. 물론 다음 강의에 useMemo나 useCallback으로 문제를 해결하겠지만, 제가 생각한 동작 순서가 맞는지 궁금합니다.
코드
import React, { useEffect, useRef, useState, useMemo } from 'react'
import Ball from './Ball'
function getWinNumbers() {
console.log('getWinNumbers함수')
const candidate = Array(45)
.fill()
.map((v, i) => i + 1)
const shuffle = []
while (candidate.length > 0) {
shuffle.push(
candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]
)
}
const bonusNumber = shuffle[shuffle.length - 1]
const winNumbers = shuffle.slice(0, 6).sort((p, c) => p - c)
return [...winNumbers, bonusNumber]
}
const Lotto = () => {
const [winNumbers, setWinNumbers] = useState(getWinNumbers())
const [winBalls, setWinBalls] = useState([])
const [bonus, setBonus] = useState(null)
const [redo, setRedo] = useState(false)
const timeouts = useRef([])
useEffect(() => {
console.log('useEffect1')
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls(prevState => [...prevState, winNumbers[i]])
}, (i + 1) * 1000)
}
timeouts.current[6] = setTimeout(() => {
setBonus(winNumbers[6])
setRedo(true)
}, 7000)
return () => {
timeouts.current.forEach(v => {
clearTimeout(v)
})
}
}, [timeouts.current]) // 빈 배열이면 componentDidMount와 동일
// 배열에 요소가 있으면 componentDidMount랑 componentDidUpdate 둘 다 수행
useEffect(() => {
console.log('useEffect2 - 로또 숫자를 생성합니다.')
}, [winNumbers])
const onClickRedo = () => {
console.log('onClickRedo')
setWinNumbers(getWinNumbers())
setWinBalls([])
setBonus(null)
setRedo(false)
timeouts.current = []
}
return (
<>
<div>Win Numbers</div>
<div id="결과창">
{winBalls.map(v => (
<Ball key={v} number={v} />
))}
</div>
<div>Bonus!</div>
{bonus && <Ball number={bonus} />}
{redo && <button onClick={onClickRedo}>One more</button>}
</>
)
}
export default Lotto
동작 결과 콘솔
11:46:54.502 Lotto.jsx:5 getWinNumbers함수
11:46:54.532 Lotto.jsx:28 useEffect1
11:46:54.532 Lotto.jsx:47 useEffect2 - 로또 숫자를 생성합니다.
11:46:55.951 Lotto.jsx:5 getWinNumbers함수
11:46:56.942 Lotto.jsx:5 getWinNumbers함수
11:46:57.729 Lotto.jsx:5 getWinNumbers함수
11:46:58.536 Lotto.jsx:5 getWinNumbers함수
11:46:59.535 Lotto.jsx:5 getWinNumbers함수
11:47:00.545 Lotto.jsx:5 getWinNumbers함수
11:47:01.536 Lotto.jsx:5 getWinNumbers함수
예측한 동작 순서
1. 함수 컴포넌트에 있는 winNumbers가 getWinNumbers 함수 호출하면서 getWinNumbers함수속 console 출력 -> 'getWinNumbers함수'
2. 27번줄의 useEffect의 두번째 인자인 timeouts.current가 [] 이기 때문에 첫번쨰 useEffect의 console 출력 -> 'useEffect1'
3. 46번줄의 useEffect의 두번째 인자인 winNumbers가 7개의 배열요소가 들어있기 때문에 true 이다 그래서 두번째 useEffect의 console 출력 -> 'useEffect2 - 로또 숫자를 생성합니다.'
4. useEffect1이 출력될때 아래 코드가 6번 동작해서 getWinNumbers함수 속에있는 console 출력 -> 'getWinNumbers함수' x 6
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls(prevState => [...prevState, winNumbers[i]])
}, (i + 1) * 1000)
}
그리고 아래 코드가 한번 동작해서 getWinNumbers함수 속에있는 console 출력 -> 'getWinNumbers함수'
timeouts.current[6] = setTimeout(() => {
setBonus(winNumbers[6])
setRedo(true)
}, 7000)
동작 순서 4번에서 (setWinBalls)와 (setBonus + setRedo)가 비동기함수 라서 앞선 콘솔들이 찍히고 마지막에 찍혔던 거죠?
답변을 작성해보세요.
답변 1