가위바위보에서 굳이 useEffect나 componentDidMount 에서만 setInterval을 사용하는건 아니고, 필요할 때 setInterval을 쓰고 componentWillUnMount에서 정리만 잘하면 된다.
Hooks는 함수 컴포넌트를 말하는 것이 아니라 useEffect, useState 같은 것들을 말하는 것이다.
Lotto.jsx (내가 만든 코드 + 강의코드)
import React, {Component} from "react";
import Ball from "./Ball";
const winBall = () => {
const balls = Array(45).fill(0).map((v,i) => i+1);
const result = [];
while(balls.length > 0){
const randIndex = Math.floor(Math.random() * balls.length); // <= 0 x < length
result.push(balls.splice(randIndex, 1)[0]);
}
const bonus = result[result.length - 1]; //맨 마지막
const wins = result.slice(0,6).sort((a,b)=>a-b); // 0~5
console.log(wins, bonus);
return [...wins, bonus];
}
class Lotto extends Component{
state = {
winNumbers: winBall(),
winBalls:[],
bonus:null,
redo:false,
}
timeouts=[];
componentDidMount() {
console.log('componentDidMount')
this.startLotto();
}
onClickRedo = () => {
this.setState({
winNumbers: winBall(),
winBalls:[],
bonus:null,
redo:false
});
this.timeouts = [];
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.state.winBalls.length === 0){
this.startLotto();
}
}
componentWillUnmount() {
this.timeouts.forEach(v => clearTimeout(v));
}
startLotto = () => {
const length = this.state.winNumbers.length - 1;
for(let i=0; i<length; i++){
const timerId = setTimeout(()=>{
this.setState((prev)=>{
const winBall = prev.winNumbers.slice(i,i+1)[0];
return {
winNumbers:[...prev.winNumbers],
winBalls:[...prev.winBalls, winBall],
bonus:null,
redo:false
}
});
},1000 * (i+1));
this.timeouts.push(timerId);
}
this.timeouts[6] = setTimeout(()=>{
this.setState({bonus: this.state.winNumbers[length],redo:true});
}, 1000 * this.state.winNumbers.length);
}
render() {
const {winNumbers, winBalls, bonus, redo} = this.state;
return (
<>
{winBalls.map(v=><Ball number={v} key={v+1}/>)}
{
bonus && <><div className="bonus__comment">보너스!</div><Ball number={bonus} /></>
}
{
redo && <button onClick={this.onClickRedo}>한번더!</button>
}
</>
)
}
}
export default Lotto;
Ball.jsx
import React, {memo} from 'react';
const Ball = memo(({number})=>{
let background, color = null;
if(number >= 40){
background = 'red';
}else if(number >= 30){
background = 'green';
}else if(number >= 20){
background = 'yellow';
}else if(number >= 10){
background = 'blue';
color = 'white';
}else{
background = 'aqua';
}
return (
<>
<div className="ball" style={{background, color}}>
{number}
</div>
</>
)
});
export default Ball;
LottoHooks.jsx
import React, {useEffect, useRef, useState} from "react";
import Ball from "./Ball";
const LottoHooks = () => {
const winBall = () => {
const balls = Array(45).fill(0).map((v,i) => i+1);
const result = [];
while(balls.length > 0){
const randIndex = Math.floor(Math.random() * balls.length); // <= 0 x < length
result.push(balls.splice(randIndex, 1)[0]);
}
const bonus = result[result.length - 1]; //맨 마지막
const wins = result.slice(0,6).sort((a,b)=>a-b); // 0~5
console.log(wins, bonus);
return [...wins, bonus];
}
const [winNumbers, setWinNumbers] = useState(winBall);
const [winBalls, setWinBalls] = useState([]);
const [bonus, setBonus] = useState(null);
const [redo,setRedo] = useState(false);
const timerRef = useRef([]);
useEffect(()=>{
for(let i=0; i<6; i++){
const timerId = setTimeout(()=>{
setWinBalls((prev)=>{
return [...prev, winNumbers[i]];
});
},(i+1) * 1000);
timerRef.current.push(timerId);
}
timerRef.current[6] = setTimeout(()=>{
setBonus(winNumbers[6]);
setRedo(true);
},7000);
},[winNumbers]);
const onClickRedo = (param) => (e) => {
console.log(param);
console.log(e.target);
setWinBalls([]);
setWinNumbers(winBall);
setBonus(null);
setRedo(false);
timerRef.current = [];
}
return (
<>
{
winBalls.map((v,i) => <Ball number={v} key={v+i}/>)
}
{
bonus && <><div>보너스!!</div><Ball number={bonus} /></>
}
{
redo && <button onClick={onClickRedo(1)}>한번더</button>
}
</>
);
}
export default LottoHooks;