반복문을 기점으로 컴포넌트를 쪼개기
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>}
</>
);
}
setTimeout을 배열에 넣어서 한꺼번에 unmount
runTimeouts = () => {
console.log('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,
});
}, 7000);
};
componentDidMount() {
console.log('didMount');
this.runTimeouts();
console.log('로또 숫자를 생성합니다.');
}
componentWillUnmount() {
this.timeouts.forEach((v) => {
clearTimeout(v);
});
}
ComponentDidUpdate
클래스 컴포넌트에서는 ComponentDidUpdate 를 사용해서 업데이트를 관리한다.
prevState에는 바뀌기 이전 state 가 저장되어있다.
ComponentDidUpdate 는 매번 실행되므로 if 문으로 분기처리를 잘해주어야한다.
componentDidUpdate(prevProps, prevState) {
console.log('didUpdate');
if (this.state.winBalls.length === 0) {
this.runTimeouts();
}
if (prevState.winNumbers !== this.state.winNumbers) {
console.log('로또 숫자를 생성합니다.');
}
}
함수형 컴포넌트에서 useRef
timeouts 라는 변수에 useRef([]) 로 선언을 해주면 timeouts.current[i] 처럼 배열에 저장을 할 수 있게 된다.
const Lotto = () => {
...
const timeouts = useRef([]);
useEffect(() => {
console.log('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와 동일
// 배열에 요소가 있으면 componentDidMount랑 componentDidUpdate 둘 다 수행
useCallback 을 꼭 사용해야할때는
자식 컴포넌트에 props 넘길때, 자식은 부모의props 가 업데이트 되면 다시 렌더링 되기 때문에 useCallback 을 처리를 꼭 해줘야한다.
만약 함수형 컴포넌트에서 componentDidUpdate 만 하고 싶다면?
다음 패턴을 사용하면 된다.
const mounted = useRef(false);
useEffect(()=> {
if (!mounted.current){
mounted.current = true;
} else {
}
},[]);
여기서 잠깐
state 가 변경될때에 화면이 리렌더링이 된다. 이렇게 어떠한 변수를 사용하고 싶을때 리렌더링 되는 것이 문제가 된다면,
const mounted = useRef(false) 와 같이 useRef 를 사용할 수 있다.
그리고 값을 변경하고 싶을때는 mounted.current = true 와 같은 방법으로 값을 할당해주면 된다.
useState 에서 일급함수 사용
function getWinNumbers() {
…
}
const Lotto = () => {
const [winNumbers, setWinNumbers] = useState(getWinNumbers());
}
function getWinNumbers() {
…
}
const Lotto = () => {
const [winNumbers, setWinNumbers] = useState(getWinNumbers);
}
다음과 같은 2개의 코드가 있을때 첫번째 코드는 리렌더를 될때마다 함수가 실행되었다.
두번째 코트는 그렇지 않고 한번만 실행되는 이유가 궁금했다.
첫번째 코드 같은 경우에는 의도적으로 getWinNumbers() 를 실행하였으므로 리렌더 될때마다 함수가 실행되는 것은 당연한 것이였다.
두번째 코드는 useState(getWinNumbers) 이렇게 함수를 넘겻을때는 useState가 처음에만 함수를 호출한다.
실행한 값을 전달하느냐 , 함수 자체를 전달하느냐의 차이이다.
또한 두번째 코드는 다음의 useMemo를 사용한 코드와 같은 역할을 한다.
function getWinNumbers() {
…
}
const Lotto = () => {
const lottoNumbers = useMemo(()=> getWinNumbers(), [])
const [winNumbers, setWinNumbers] = useState(lottoNumbers);
}
https://codesandbox.io/s/wonderful-surf-cpysoc?file=/src/Lotto.jsx
'공부기록 > 웹 개발' 카테고리의 다른 글
png 파일 색 변경하는 방법 (0) | 2022.08.31 |
---|---|
조금의 sass 그리고 css module (0) | 2022.08.29 |
[웹 게임을 만들며 배우는 React] 5장 (0) | 2022.08.29 |
[웹 게임을 만들며 배우는 React] 4장 (0) | 2022.08.26 |
[웹 게임을 만들며 배우는 React] 3장 (0) | 2022.08.25 |