일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- intellij
- vs code 내 node
- Do it 자바스크립트 + 제이쿼리 입문
- 따라하며 배우는 노드 리액트 기본 강의
- intllij 내 Bean을 찾지 못해서 발생하는 오류
- You are importing createRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client"
- props
- node.js로 로그인하기
- googleColaboratory
- 인프런
- Spring-Framework
- node.js 설치
- react오류
- spring-boot
- react
- 웹 게임을 만들며 배우는 리액트
- Concurrently
- 모던자바스크립트
- ReactDOM.render is no longer supported in React 18. Use createRoot instead
- Python
- DB Browser
- 모두의 파이썬
- 거북이 대포 게임
- 노드에 리액트 추가하기
- Colaboratory 글자 깨짐
- 타자 게임 만들기
- 자바스크립트
- 계산맞추기 게임
- 리액트
- JS 개념
- Today
- Total
프로그래밍 삽질 중
[웹 게임을 만들며 배우는 React] - 가위바위보, 라이프사이클 본문
출처: https://www.inflearn.com/course/web-game-react/dashboard
* 라이프 사이클(컴포넌트의 일생)
- 컴포넌트(SPClass.jsx)가 클라이언트(client.jsx)에서 불려와서 렌더링됨
- 컴포넌트가 DOM에 붙는 순간이 있음
- 특정한 동작 가능
▶ class에서는 아래의 3개가 담당한다면 함수 컴포넌트에서는 useEffect가 이 역할을 담당(1대1 대응은 아님)
componentDidMount | componentWillUnmount | componentWillUnmount |
렌더링이 처음, 성공적으로 실행 시 실행 리렌더링이 일어날 때는 실행되지 않음 |
컴포넌트가 제거되기 직전 | 리렌더링 후에 실행 |
* 클래스의 경우
- componentDidMount나 componentDidUpdate에서 모든 state를 조건문으로 분기 처리함
constructor => render => ref => componentDidMount => setState나 props 바뀔 때 => shoudComponentUpdate
=> render => componentDidUpdate => 부모가 나(자식컴포넌트)를 없앨 때 => componentWillUnmount
* 비동기 요청
- setInterval 일정 시간마다 반복작업
=렌더링 후 계속 반복작업(누가 취소하지 않음 => 웹사이트 끌 때까지 계속 실행되는 중)
- RSP가 계속 DOM에 붙었다 땟다 하면 기존의 setInterval이 점점 더 많이 생김
- 메모리를 계속 먹음(메모리 누수)
- 완료되지 않은 비동기는 componentWillUnmount에서 정리해야 함
* 클로저 문제
- 비동기 안에서 바깥에 있는 변수 참조 시 발생
//클로저
//const { imgCoord } = this.state; //여기에 위치하면 클로저 문제 발생
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.바위,
});
}
};
* 고차함수 (아래의 예시는 함수의 형태로 리턴하기 위해 고차함수를 사용한 것)
- 함수 안에 함수 호출하는 부분이 들어 있음
▶ 함수를 인자로 받을 수 있고, 함수의 형태로 리턴할 수 있음
▶ 추상화 작업(복잡한 어떤 것을 압축해 핵심만 추출)을 통해 함수를 전달받거나 함수를 리턴함
//고차함수
onClickBtn = (choice) => () => {
const { imgCoord } = this.state;
clearInterval(this.interval);
const myScore = scores[choice];
const comScore = scores[computerCoice(imgCoord)];
const diff = myScore - comScore;
if (diff === 0) {
this.setState({
result: "비겼습니다.",
});
} else if ([-1, 2].includes(diff)) {
this.setState((prevState) => {
return {
result: "이겼습니다!",
score: prevState.score + 1,
};
});
} else {
this.setState((prevState) => {
return {
result: "졌습니다!",
score: prevState.score - 1,
};
});
}
setTimeout(() => {
this.interval = setInterval(this.changeHand, 1000);
}, 1000);
};
<button id="paper" className="btn" onClick={this.onClickBtn("보")}>
//고차함수가 아니라 onClickBtn = (choice) => {} 일 경우
// <button id="paper" className="btn" onClick={() => this.onClickBtn("보")}>
* class 사용 [RSPClass.jsx]
import React, { Component } from "react";
const rspCoords = {
바위: "0",
가위: "-142px",
보: "-284px",
};
const scores = {
가위: 1,
바위: 0,
보: -1,
};
const computerCoice = (imgCoord) => {
return Object.entries(rspCoords).find(function (v) {
return v[1] === imgCoord;
})[0];
};
class RSPClass extends Component {
state = {
result: "",
imgCoord: rspCoords.바위,
score: 0,
};
//interval 문제 해결
interval;
componentDidMount() {
this.interval = setInterval(this.changeHand, 100);
} //비동기요청
componentWillUnmount() {
//비동기요청 정리
clearInterval(this.interval);
}
// componentDidUpdate() {}
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.바위,
});
}
};
onClickBtn = (choice) => () => {
const { imgCoord } = this.state;
clearInterval(this.interval);
const myScore = scores[choice];
const comScore = scores[computerCoice(imgCoord)];
const diff = myScore - comScore;
if (diff === 0) {
this.setState({
result: "비겼습니다.",
});
} else if ([-1, 2].includes(diff)) {
this.setState((prevState) => {
return {
result: "이겼습니다!",
score: prevState.score + 1,
};
});
} else {
this.setState((prevState) => {
return {
result: "졌습니다!",
score: prevState.score - 1,
};
});
}
setTimeout(() => {
this.interval = setInterval(this.changeHand, 1000);
}, 1000);
};
render() {
const { result, score, imgCoord } = this.state;
return (
<>
<div
id="computer"
style={{
background: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0`,
}}
/>
<div>
<button id="rock" className="btn" onClick={this.onClickBtn("바위")}>
바위
</button>
<button
id="scissor"
className="btn"
onClick={this.onClickBtn("가위")}
>
가위
</button>
<button id="paper" className="btn" onClick={this.onClickBtn("보")}>
보
</button>
</div>
<div>{result}</div>
<div>현재 {score}점</div>
</>
);
}
}
export default RSPClass;
* Hooks 사용
- useEffect(class의 componentDidMount나 componentDidUpdate 역할 담당)
▶ 첫번째 파라미터에는 함수, 두번째 파라미터에는 의존값이 들어있는 배열 (deps)을 넣음
▶ 배열에는 꼭 useEffect를 다시 실행할 값만 넣을 것
▶ 두번째 배열에 넣은 이미지가 실행될 때마다(반복) setInterval같은 효과
▶ 두 번째 배열을 비워놓는 건(componentDIdMount) 처음에만 실행되고 다음 것은 바뀌지 않음
▶ 두 번째 배열에 값을 넣으면 componentDidUpdate 효과
참고 : https://react.vlpt.us/basic/16-useEffect.html
import React, { useState, useRef, useEffect } from "react";
const rspCoords = {
바위: "0",
가위: "-142px",
보: "-284px",
};
const scores = {
가위: 1,
바위: 0,
보: -1,
};
const computerCoice = (imgCoord) => {
return Object.entries(rspCoords).find(function (v) {
return v[1] === imgCoord;
})[0];
};
const RSP = () => {
const [result, setResult] = useState("");
const [imgCoord, setImgCoord] = useState(rspCoords.바위);
const [score, setScore] = useState(0);
const interval = useRef();
useEffect(() => {
//함수
//componentDidMount, componentDidUpdate 역할(1대1 대응은 아님)
console.log("다시 실행");
interval.current = setInterval(changeHand, 100);
return () => {
console.log("종료");
//componentWillUnmount 역할
clearInterval(interval.current);
};
}, [imgCoord]); //배열(두 번째 인수 배열에 넣은 값들이 바뀔 때 useEffect 실행됨)
const changeHand = () => {
if (imgCoord === rspCoords.바위) {
setImgCoord(rspCoords.가위);
} else if (imgCoord === rspCoords.가위) {
setImgCoord(rspCoords.보);
} else if (imgCoord === rspCoords.보) {
setImgCoord(rspCoords.바위);
}
};
const onClickBtn = (choice) => () => {
clearInterval(interval.current);
const myScore = scores[choice];
const comScore = scores[computerCoice(imgCoord)];
const diff = myScore - comScore;
if (diff === 0) {
setResult("비겼습니다");
} else if ([-1, 2].includes(diff)) {
setResult("이겼습니다!");
setScore((prevScore) => prevScore + 1);
} else {
setResult("졌습니다!");
setScore((prevScore) => prevScore - 1);
}
setTimeout(() => {
interval.current = setInterval(changeHand, 100);
}, 1000);
};
return (
<>
<div
id="computer"
style={{
background: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0`,
}}
/>
<div>
<button id="rock" className="btn" onClick={onClickBtn("바위")}>
바위
</button>
<button id="scissor" className="btn" onClick={onClickBtn("가위")}>
가위
</button>
<button id="paper" className="btn" onClick={onClickBtn("보")}>
보
</button>
</div>
<div>{result}</div>
<div>현재 {score}점</div>
</>
);
};
export default RSP;
'과거 프로그래밍 자료들 > React' 카테고리의 다른 글
[웹 게임을 만들며 배우는 React] - 로또추첨기, useEffect, useCallback (1) | 2022.09.29 |
---|---|
[웹 게임을 만들며 배우는 React] - 가위바위보, 커스텀 훅 (0) | 2022.09.29 |
[웹 게임을 만들며 배우는 React] - 반응속도 체크, state와 ref 차이 (0) | 2022.09.28 |
[웹 게임을 만들며 배우는 React] - ref, props (0) | 2022.09.28 |
[웹 게임을 만들며 배우는 React] - 숫자야구(useState), 렌더링 문제 (0) | 2022.09.28 |