티스토리 뷰
// class
// Lotto.jsx
import React, { Component } 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];
}
class Lotto extends Component {
state = {
winNumbers: getWinNumbers(), // 당첨 숫자들
winBalls: [],
bonus: null, // 보너스 공
redo: false,
};
timeouts = [];
runTimeouts = () => {
const { winNumbers } = this.state;
for (let i = 0; i < winNumbers.length - 1; i++) {
this.timeouts[i] = setTimeout(() => {
this.setState((prevState) => {
return {
winBalls: [...prevState.winBalls, winNumbers[i]]
}
});
}, (i + 1) * 1000);
}
this.timeouts[6] = setTimeout(() => {
this.setState({
bonus: winNumbers[6],
redo: true, // true 값이 되어서 한번 더 버튼이 보이게 됨
});
}, 7000);
}
componentDidMount() {
this.runTimeouts();
}
componentDidUpdate(prevProps, prevState) {
if (this.state.winBalls.length === 0) { // 조건문이 중요! 이에 따라 실행되기 때문에, hooks랑 다를 수 있음
this.runTimeouts();
}
}
componentWillUnmount() {
this.timeouts.forEach((v) => {
clearTimeout(v);
})
}
onClickRedo = () => { // 다시 시작은 초기화
this.setState({
winNumbers: getWinNumbers(),
winBalls: [],
bonus: null,
redo: false,
})
this.timeouts = []; // 타임아웃도 초기화
};
render() {
const { winBalls, bonus, redo } = this.state;
return (
<>
<div>당첨숫자</div>
<div id="결과창">{winBalls.map((v) => <Ball key={v} number={v} />)}</div>
<div>보너스</div>
{bonus && <Ball number={bonus} />}
{redo && <button onClick={this.onClickRedo}>한 번 더!</button>}
</>
);
}
}
export default Lotto;
// ball.jsx
import React, { PureComponent } from 'react';
class Ball extends PureComponent {
render() {
const {number} = this.props;
let background;
if (number <= 10) {
background = 'red';
} else if (number <= 20) {
background = 'orange';
} else if (number <= 30) {
background = 'yellow';
} else if (number <= 40) {
background = 'blue';
} else {
background = 'green';
}
return (
<div className="ball" style={{ background }}>{number}</div>
);
}
}
export default Ball;
useEffect, useMemo, useCallback
useEffect(() => {
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]]);
}, (i + 1) * 1000);
}
timeouts.current[6] = setTimeout(() => {
setBonus(winNumbers[6]);
setRedo(true);
}, 7000);
return () => {
timeouts.current.forEach((v) => {
clearTimeout(v);
});
}
}, []); // componentDidMount를 수행
----------------------------------------------------------------------------------
useEffect(() => {
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls((prevBalls) => [...prevBalls, 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와 componentDidUpdate를 모두 수행
useEffect, useMemo, useCallback은 두번째 인자를 가짐
두번째 인자를 가지지 않으면 다시 실행되지 않음
[] 두번째 인자가 매우 중요!!! 언제 다시 실행할지를 정하기 때문에!!!!
hooks는 선언순서와 실행순서를 같도록 해야하기 때문에 무조건 최상위
조건문 안에 절대 넣으면 안됨
함수나 반복문 안에도 되도록 넣지 말 것
useEffect에서
componentDidMount는 실행하지 않고 componentDidUpdate만 실행하고 싶다!
이렇게 할 수 있음
const mounted = useRef(false);
useEffect(() => {
if (!mounted.current) {
mounted.current = true;
} else {
// 원하는 동작
}
}, [바뀌는값])
useMemo 복잡한 함수 결과값을 기억
useRef 단순한 결과값을 기억
useMemo 함수의 return값을 기억
useCallback 함수 자체를 기억
useCallback을 사용하면 좋은 점
함수 컴포넌트는 전체가 재실행되는데 함수 자체를 기억해둬서
컴포넌트가 새로 실행되어도 함수가 새로 생성되지 않는다
> 함수 생성 자체가 비용이 클 때 함수 자체를 기억해둬서 넣는 것
필수로 해야할 때 자식 컴포넌트에 props로 함수를 넘길 때는 useCallback 필수
> 하지 않으면 자식 컴포넌트가 계속 리렌더링 됨
새로운 값을 가져오는 경우에 useCallback을 사용하면 처음 값만을 기억하기 때문에 주의!
그래서 []input에 변하는 값을 알아채 새로 실행되도록 인자를 넣어줘야함
// hooks
// Lotto.jsx
import React, { useState, useRef, useEffect, useMemo,useCallback } from 'react';
import Ball from './Ball-class';
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 lottoNumbers = useMemo(() => getWinNumbers(), []);
const [winNumbers, setWinNumbers] = useState(lottoNumbers);
const [winBalls, setWinBalls] = useState([]);
const [bonus, setBonus] = useState(null);
const [redo, setRedo] = useState(false);
const timeouts = useRef([]);
const onClickRedo = () => {
setWinNumbers(getWinNumbers());
setWinBalls([]);
setBonus(null);
setRedo(false);
timeouts.current = [];
};
useEffect(() => {
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]]);
}, (i + 1) * 1000);
}
timeouts.current[6] = setTimeout(() => {
setBonus(winNumbers[6]);
setRedo(true);
}, 7000);
return () => {
timeouts.current.forEach((v) => {
clearTimeout(v);
});
}
}, [timeouts.current]);
return (
<>
<div>당첨숫자</div>
<div id="결과창">{winBalls.map((v) => <Ball key={v} number={v} />)}</div>
<div>보너스</div>
{bonus && <Ball number={bonus} />}
{redo && <button onClick={onClickRedo}>한 번 더!</button>}
</>
);
}
export default Lotto;
// Ball.jsx
import React, {memo} from 'react';
const Ball = memo(({ number }) => {
let background;
if (number <= 10) {
background = 'red';
} else if (number <= 20) {
background = 'orange';
} else if (number <= 30) {
background = 'yellow';
} else if (number <= 40) {
background = 'blue';
} else {
background = 'green';
}
return (
<div className="ball" style={{ background }}>{number}</div>
);
});
export default Ball;
728x90
'유튜브 강의' 카테고리의 다른 글
제로초 리액트 강의 8 Context API (0) | 2021.11.28 |
---|---|
제로초 리액트 강의 7 useReducer, 성능최적화 (0) | 2021.11.17 |
제로초 리액트 강의 5.2 가위바위보 만들기 (0) | 2021.11.16 |
제로초 리액트 강의 5.1 리액트 라이프 사이클, 고차 함수, useEffect (0) | 2021.11.16 |
제로초 리액트 강의 4 React 반복문, 반응속도 체크 만들기 (0) | 2021.11.15 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 회고
- 깃
- vue
- js
- React
- 파이썬
- 저스트코드
- Til
- 리액트
- 비주얼스튜디오코드
- Typescript
- 타입스크립트
- 드림코딩
- html
- 김버그
- 제이쿼리
- 자바스크립트
- vscode
- Python
- 코드잇
- TS
- 스파르타코딩클럽
- javascript
- 제로초
- 코딩앙마
- map
- git
- CSS
- 구름에듀
- scss
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함