강의를 통해 배운 점
useEffect에 대해 알고 있었고, 사용법 또한 알고 있었습니다. 프로젝트에서 문제없이 사용했고, 항상 의도한 대로 사용되어 왔습니다. 하지만 강의에서 오류가 생기는걸 보았고, 나는 문제가 없는데 강의에선 왜 문제가 생겼지? 라는 의문이 생겼습니다.
공식문서를 뒤져보니 강의에서의 설명이 맞았고 (rendering될 때마다 useEffect 콜백이 실행이 되고 clean-up또한 실행이 된다.는 내용) 이게 지금도 이해는 안가지만 어쨋든 공식문서에 나와 있는 것처럼 이럼에도 불구하고 문제가 안생긴것은 디펜던시 배열에 빌드 시 자동으로 추가 될 수 있기 때문이라는 것도 배웠습니다.
강의를 보고 나서 오히려 더 이해가 안가는 상황입니다. 지금 진짜 ~~ 이해 안되는 상황인데 일단은 넘어가야 되겠습니다. 다음에 다시 봐야할것 같아요. ㅠㅠ
아마 React가 버젼 업이 되면서 자동으로 빌드 시 추가되는 걸로 바뀌어서 오류가 없는 것 같은데, 추론일 뿐입니다. ... 허허..
진짜 life Cycle이 훨씬 직관적이긴 하네요. 😭
내가 짠 코드
import React, { Component } from 'react';
class RSPClass extends Component {
state = {
aiPick: '',
userPick: '',
result: '',
};
i = 0;
interval;
componentDidMount = () => this.start();
componentWillUnmount = () => clearInterval(this.interval);
start = () => {
clearInterval(this.interval);
this.interval = setInterval(() => {
this.setState({ aiPick: rsp[this.i % 3] });
this.i++;
}, 200);
this.setState({ result: '' });
};
onClick = e => {
const { aiPick, result } = this.state;
if (result) return;
clearInterval(this.interval);
this.setState({ userPick: e.target.name, result: rspResult[e.target.name][aiPick] });
};
render() {
return (
<>
<h1>가위 바위 보! - {this.state.result}</h1>
<div
className={'image'}
style={{
backgroundPosition: rspCoords[this.state.aiPick],
}}
></div>
{rsp.map(el => (
<button key={el} onClick={this.onClick} name={el}>
{el}
</button>
))}
<br />
<button onClick={this.start}>다시 시작</button>
</>
);
}
}
export default RSPClass;
const rsp = ['바위', '가위', '보'];
const rspCoords = {
바위: '0',
가위: '-142px',
보: '-284px',
};
const rspResult = {
바위: { 바위: '비겼다!', 가위: '이겼다!', 보: '졌다 😭' },
가위: { 가위: '비겼다!', 보: '이겼다!', 바위: '졌다 😭' },
보: { 보: '비겼다!', 바위: '이겼다!', 가위: '졌다 😭' },
};
i가 number의 최댓값보다 넘어가면 overflow 뜨겠네요! ㅎㅎ
componentDidMount() 일 때 this.start()를 호출하는건 잘해줬는데, componentWillUnmount() 일 때, clearInterval을 안해줬었습니다! 제로초 님 코드 보고 추가했어요!
클래스 컴포넌트의 라이프 사이클
import React, { Component } from 'react';
// 클래스 컴포넌트의 라이프 사이클
// 생성 : constructor => render => ref => componentDidMount
// 갱신 : => (state/props 바뀔 때 => shouldComponentUpdate(true) => render => componentDidUpdate)
// 제거 : 부모가 나를 없앴을 때 => componentWillUnmount => 소멸
class RSPClass extends Component {
// 컴포넌트가 첫 렌더링 된 후, 여기에 비동기 요청을 많이 함
componentDidMount = () => this.start();
// 리렌더링 후
componentDidUpdate() {}
// 컴포넌트가 제거되기 직전, 비동기 요청 정리를 많이 함
componentWillUnmount = () => clearInterval(this.interval);
...
render() {
return (
<>
...
</>
);
}
}
export default RSPClass;
componentDidMount() ⇒ 컴포넌트의 첫 렌더링 후
componentDidUpdate() ⇒ 리렌더링 후
componentWillUnmount() ⇒ 컴포넌트가 제거되기 직전
주석만 잘 봐도 라이프 사이클은 다 이해할 수 있습니다. 굳!
강의 코드 해석
componentDidMount() { // 컴포넌트가 첫 렌더링된 후, 여기에 비동기 요청을 많이 해요
this.interval = setInterval(this.changeHand, 100);
}
componentWillUnmount() { // 컴포넌트가 제거되기 직전, 비동기 요청 정리를 많이 해요
clearInterval(this.interval);
}
changeHand = () => {
const {imgCoord} = this.state;
if (imgCoord === rspCoords.바위) {
this.setState({
imgCoord: rspCoords.가위,
});
} else if (imgCoord === rspCoords.가위) {
this.setState({
imgCoord: rspCoords.보,
});
} else if (imgCoord === rspCoords.보) {
this.setState({
imgCoord: rspCoords.바위,
});
}
};
저는 i라는 변수를 둬서 012 012 012 로 선택되도록 했는데요.
강의에선 changeHand라는 함수를 만들고, 이 함수는 지금의 값을 이용해 다음값을 정해주는 형태로 했네요.
React에서 많이 쓰이는 패턴
onClick = (pattern) => {
return pattern
}
<div onClick={() => this.onClick('바위')}></div>
위 코드 중 아래 div 안과 같이 애로우 펑션이 있을 때, 아래 코드블럭과 같이 고쳐주면 같은 코드를 만들 수 있습니다.
onClick = (pattern) => () => {
return pattern
}
<div onClick={this.onClick('바위')}></div>
이런걸 하이어 오더 펑션, 고차 함수 라고 하는데 실무에서 많이 쓰인다고 한다.
근데 솔찍히 이거 명확히 이해 안되는데 많이 보다 보면 이해 되겠지?
이해 안되는 점
데브 툴즈로 리렌더링 확인할 때 제로초님은 아래 버튼들은 쓸데없이 리렌더링 되지 않는다.
근데 난 왜 버튼들이 리렌더링이 되는거지?
이거 이상한게 아까부터 계속적으로 이런일이 발생해서 뭔가 문제가 있는것 같다.
✅ 아쉽게도 버전 문제 때문에 하이라이트가 되는걸로 바뀌었다고 하네요. 왠지 아쉽네요. 그럼 데브툴즈를 사용해도 리렌더링을 정확히 캐치하지 못하는거네요.
함수 컴포넌트로 구현한 내 코드
import React, { useEffect, useRef, useState } from 'react';
function RSP() {
const [aiPick, setAiPick] = useState('');
const [userPick, setUserPick] = useState('');
const [result, setResult] = useState('');
const i = useRef(0);
const interval = useRef();
useEffect(() => {
start();
return () => {
clearInterval(interval.current);
};
}, []);
const start = () => {
clearInterval(interval.current);
interval.current = setInterval(() => {
setAiPick(rsp[i.current % 3]);
i.current++;
}, 200);
setResult('');
};
const onClick = e => {
if (result) return;
clearInterval(interval.current);
setUserPick(e.target.name);
setResult(rspResult[e.target.name][aiPick]);
setTimeout(() => {
start();
}, 2000);
};
return (
<>
<h1>훅스 가위 바위 보! - {result}</h1>
<div
className={'image'}
style={{
backgroundPosition: rspCoords[aiPick],
}}
></div>
{rsp.map(el => (
<button key={el} onClick={onClick} name={el}>
{el}
</button>
))}
<br />
<button onClick={start}>다시 시작</button>
</>
);
}
export default RSP;
const rsp = ['바위', '가위', '보'];
const rspCoords = {
바위: '0',
가위: '-142px',
보: '-284px',
};
const rspResult = {
바위: { 바위: '비겼다!', 가위: '이겼다!', 보: '졌다 😭' },
가위: { 가위: '비겼다!', 보: '이겼다!', 바위: '졌다 😭' },
보: { 보: '비겼다!', 바위: '이겼다!', 가위: '졌다 😭' },
};
바뀐게 거의 없습니다. 사실 클래스 컴포넌트, 함수 컴포넌트 둘 다 사용할 줄 안다면 거의 동일한 코드라고 봐도 될것 같습니다. 생활코딩에서 클래스 컴포넌트를 처음 만났을 땐 굉장히 당황스러웠었는데 이제는 그냥 “별 다를게 없다” 라는 생각이 드네요.
변경점 1) 단순 변수는 useRef를 사용했습니다.
변경점 2) 라이프사이클 메서드 대신 useEffect를 사용했습니다.
useEffect 강의 중
useEffect 강의 중 이상한 부분이 있던데 원인파악은 정확히 안됩니다. 일단 제 코드에서와 다르게 움직이기 때문에 .. 이해할 수 없고, 저는 의도한 대로 코딩을 했는데 문제 없이 진행이 되어서요.
setTimeout을 하고 return 에 클린업으로 clear해주는 코드를 짜셨는데 왜 바로 클린업이 되는지 모르겠네요.
빌드 시 자동으로 dependency 배열에 추가되어서 강의랑 다르게 오류가 없었던 것 같은데, 이걸 확인할 방법이 없다. 웹팩에서 소스맵을 설정해서 직접 추가된 디펜던시를 보고싶었는데, 소스맵이 자꾸 안보여서 … 일단 오늘은 자러 갑니다.
'FrontEnd > React.js' 카테고리의 다른 글
[React.js] 제로초 웹게임 - 6. 로또 (useCallback, useMemo) (0) | 2022.12.01 |
---|---|
[React.js] useContext 찍먹, useFetch 구현, loading, error 상태 관리 (0) | 2022.10.31 |
[React.js] axios instance.interceptor를 이용한 미들처리 (0) | 2022.10.29 |
[React.js] 리팩토링 하며 생긴 질문 - axios 의 catch() 와 try-catch의 catch가 같은건가? (0) | 2022.10.28 |
[React.js] 제로초 웹게임 - 4. 반응속도체크 (useRef) (0) | 2022.10.24 |
[React.js] 제로초 웹게임 - 3. 숫자야구 (shouldComponentUpdate, React.memo) (0) | 2022.10.24 |
[React.js] 제로초 웹게임 - 2. 끝말잇기 (Webpack, Babel) (0) | 2022.10.22 |
[React.js] 제로초 웹게임 - 1. 구구단 (react, babel) (0) | 2022.10.21 |
댓글