리액트 정리
[로또추첨기] useEffect, useMemo, useCallback 코드부분 + Hooks 코드 완성 + Class 코드 본문
리액트/웹게임
[로또추첨기] useEffect, useMemo, useCallback 코드부분 + Hooks 코드 완성 + Class 코드
버그킴 2020. 2. 27. 14:201. useEffect
- effect = componentDidMount로 수행할 기능
- cleanup = componentWillUnmount로 클린업 할 기능
- input = componentDidUpdate 조건을 넣어줌. 조건에 부합할 때 componentDidMount + componentDidUpdate 까지실행 (빈 배열이면 componentDidMount만 실행)
useEffect(() => {
effect
return () => {
cleanup
};
}, [input])
작성한 코드 부분
const Lotto = () => {
const [selectedNumbers, setSelectedNumbers] = useState(getSelectedNumbers());
console.log(selectedNumbers);
const [winningNumberArr, setWinningNumberArr] = useState([]);
const [bonusNumber, setBonusNumber] = useState(null);
const [redo, setRedo] = useState(false);
const timeouts = useRef([]);
useEffect(() => {
console.log('useEffect');
for (let i = 0; i < selectedNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinningNumberArr(prevState => {
return [...prevState, selectedNumbers[i]];
});
}, (i + 1) * 1000);
}
timeouts.current[6] = setTimeout(() => {
setBonusNumber(selectedNumbers[6]);
setRedo(true);
}, 7000);
return () => {
timeouts.current.forEach(v => {
clearTimeout(v);
});
};
}, [timeouts.current]); // input이 빈 배열이면 componentDidMount와 동일하다.
....
2. Memoization
Hooks는 기본적으로 함수 컴포넌트 전체가 다같이 재실행되는데,
useMemo, useCallback 사용하면 복잡한 함수 실행한 결과값, 함수를 저장해둘 수 있다.
Hooks안에 함수가 있으면, 기본적으로 console.log하나씩 다 넣어놓고, 진짜 필요할때만 실행되는게 맞는지 확인하고 메모이제이션.
2-1. useMemo
useMemo: 함수의 리턴 값을 기억.
[]배열에 들어간 요소가 바뀌기 전까지 계속 같은 값을 갖고있는다. 콘솔찍어서 확인하면 한번만 실행됨!
const lottoNumbers = useMemo(() => getSelectedNumbers(), []);
2-2. useCallback
useCallback: 함수 자체를 기억. 부모가 자식에게 prop으로 함수를 내릴 때 사용. (안하면 계속 새 함수로 알고 리렌더링함. )
const onClickRedo = useCallback(() => {
console.log('useCallback');
console.log(selectedNumbers);
setSelectedNumbers(getSelectedNumbers());
setWinningNumberArr([]);
setBonusNumber(null);
setRedo(false);
timeouts.current = [];
}, [selectedNumbers]);
코드 완성분
더보기
LottoHooks.jsx
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Ball from './Ball';
function getSelectedNumbers() {
console.log('getSelectedNumbers');
const candidate = Array(45)
.fill()
.map((v, i) => {
return i + 1;
});
const shuffle = [];
while (candidate.length > 0) {
shuffle.push(candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]);
}
const winningNumberArr = shuffle.slice(0, 6).sort((a, b) => {
return a - b;
});
const bonusNumber = shuffle.pop();
return [...winningNumberArr, bonusNumber];
}
const Lotto = () => {
// Hooks는 기본적으로 함수 컴포넌트 전체가 다같이 재실행되는데, useMemo를 사용하면 복잡한 함수 실행한 결과값을 저장해둘 수 있다.
// useMemo: 함수의 리턴 값을 기억. ([...winningNumberArr, bonusNumber])
// []배열에 들어간 요소가 바뀌기 전까지 계속 같은 값을 갖고있는다. 콘솔찍어서 확인하면 한번만 실행됨!
// Hooks안에 함수가 있으면, 기본적으로 console.log하나씩 다 넣어놓고, 진짜 필요할때만 실행되는게 맞는지 확인하고 메모이제이션.
// useMemo : 함수의 리턴 값 기억 / useCallback: 함수 자체를 기억
const lottoNumbers = useMemo(() => getSelectedNumbers(), []);
const [selectedNumbers, setSelectedNumbers] = useState(lottoNumbers);
const [winningNumberArr, setWinningNumberArr] = useState([]);
const [bonusNumber, setBonusNumber] = useState(null);
const [redo, setRedo] = useState(false);
const timeouts = useRef([]);
useEffect(() => {
console.log('useEffect');
for (let i = 0; i < selectedNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinningNumberArr(prevState => {
return [...prevState, selectedNumbers[i]];
});
}, (i + 1) * 1000);
}
timeouts.current[6] = setTimeout(() => {
setBonusNumber(selectedNumbers[6]);
setRedo(true);
}, 7000);
return () => {
timeouts.current.forEach(v => {
clearTimeout(v);
});
};
}, [timeouts.current]); // input이 빈 배열이면 componentDidMount와 동일하다.
// useCallback
const onClickRedo = useCallback(() => {
console.log('useCallback');
console.log(selectedNumbers);
setSelectedNumbers(getSelectedNumbers());
setWinningNumberArr([]);
setBonusNumber(null);
setRedo(false);
timeouts.current = [];
}, [selectedNumbers]);
return (
<>
<p>Winning Numbers</p>
<div id='resultScreen'>
{winningNumberArr.map(v => (
<Ball key={v} number={v} />
))}
</div>
<p>Bonus Number</p>
{bonusNumber && <Ball number={bonusNumber} />}
{redo && <button onClick={redo ? onClickRedo : () => {}}>one more time? </button>}
</>
);
};
export default Lotto;
LottoClass.jsx
import React, { Component } from 'react';
import Ball from './Ball';
function selectedNumbers() {
console.log('selectedNumbers');
const candidate = Array(45)
.fill()
.map((v, i) => {
return i + 1;
});
const shuffle = [];
while (candidate.length > 0) {
shuffle.push(candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]);
}
const winningNumberArr = shuffle.slice(0, 6).sort((a, b) => {
return a - b;
});
const bonusNumber = shuffle.pop();
return { winningNumberArr: winningNumberArr, bonusNumber: bonusNumber };
}
class Lotto extends Component {
state = {
selectedNumbers: selectedNumbers(),
winningNumberArr: [],
bonusNumber: null,
redo: false,
};
timeouts = [];
runTimeouts = () => {
const { selectedNumbers } = this.state;
for (let i = 0; i < selectedNumbers.winningNumberArr.length; i++) {
this.timeouts[i] = setTimeout(() => {
this.setState(prevState => {
return { winningNumberArr: [...prevState.winningNumberArr, selectedNumbers.winningNumberArr[i]] };
});
}, (i + 1) * 1000);
}
this.timeouts[6] = setTimeout(() => {
this.setState({
bonusNumber: selectedNumbers.bonusNumber,
redo: true,
});
}, 7000);
};
// 여기서 숫자 하나씩 나오게.. 1번 .. 1, 2번... 1,2,3번...
componentDidMount() {
if (this.state.winningNumberArr.length === 0) {
this.runTimeouts();
}
}
componentWillUnmount() {
this.timeouts.forEach(v => {
clearTimeout(v);
});
}
onClickRedo = () => {
this.setState({
selectedNumbers: selectedNumbers(),
winningNumberArr: [],
bonusNumber: null,
redo: false,
});
this.timeouts = [];
this.runTimeouts();
};
render() {
const { winningNumberArr, bonusNumber, redo } = this.state;
return (
<>
<p>winning numbers</p>
<div id='resultScreen'>
{winningNumberArr.map(v => (
<Ball key={v} number={v} />
))}
</div>
<p>Bonus number</p>
{bonusNumber && <Ball number={bonusNumber} />}
{redo && <button onClick={redo ? this.onClickRedo : () => {}}>one more time? </button>}
</>
);
}
}
export default Lotto;
Ball.jsx
import React, { memo } from 'react';
const Ball = memo(({ number }) => {
let backgroundColor;
if (number <= 10) {
backgroundColor = 'red';
} else if (number <= 20) {
backgroundColor = 'orange';
} else if (number <= 30) {
backgroundColor = 'yellow';
} else if (number <= 40) {
backgroundColor = 'blue';
} else {
backgroundColor = 'green';
}
return (
<div className='ball' style={{ backgroundColor }}>
{number}
</div>
);
});
export default Ball;
'리액트 > 웹게임' 카테고리의 다른 글
[로또추첨기] Array methods - Array() fill() map() splice() slice() sort() Math.floor() Math.random() push() pop() (0) | 2020.02.27 |
---|---|
[틱택토] (in progress) (0) | 2020.02.27 |
[가위바위보] 버튼에 고차함수(High order function) 함수 연달아 쓰기 () => (0) | 2020.02.19 |
[가위바위보] setInterval과 라이프사이클 연동하기 (0) | 2020.02.18 |
[가위바위보] Component Lifecycle (0) | 2020.02.18 |