https://kojammin.tistory.com/199
위의 문제의 Dicegame 프로젝트를 만들어본 과정입니다.
◎ 1_ index.js 작성 과정 //직접적으로 출력되는 js파일
● [index.html]코드를 봤을 때, <body>태그 내 자식인 div#root 안에서 제작될 것이다.
-index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>주사위 게임</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
● 그래서, index.js는 아래와 같이 작성 시작
- import를 통해 ReactDom을 불러온다. //React 웹페이지 출력에 총 담당자 객체
- ReactDom 객체의 render()메소드로 렌더링 시작
※참고_ReactDom.render()
* React 프로젝트의 출력을 담당하는 객체 프로퍼티 메소드로써,
* 매개인자1_ 출력할 컴포넌트 태그
* 매개인자2_ html문서에서 어느 태그의 자식에서 제작할지 결정할지 경정해주는 요소노드 값
-index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render();
◎ 2_ App.js //전체적으로 DiceGame 웹페이지의 전체 컴포넌트 구조를 나타내주는 컴포넌트
- index.js의 render()에 <App>태그 하나만 출력되도록 한다. => ReactDom.render의 매개인자1에 <App>컴포넌트 태그
- 주사위 게임 출력 장면으로, <App> 컴포넌트 내의 구조를 작성해보자
- 그리고, App.js는 각 컴포넌트에서 나오는 데이터를 모두 전달 받고, 출력만 한다.
- App.js //틀만 작성한 코드
import HeadImg from './assets/logo.png';
function App() {
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div className='Button'>
</div>
<div className='Board'>
</div>
</>
);
}
export default App;
◎ 3_ Dice.js 작성 과정
● 순서1_ [src]폴더의 주사위 사진들 모두 import 하기
//주사위 사진 담당 부분
//Blue 사진
import DiceBlue01 from './assets/dice-blue-1.svg';
import DiceBlue02 from './assets/dice-blue-2.svg';
import DiceBlue03 from './assets/dice-blue-3.svg';
import DiceBlue04 from './assets/dice-blue-4.svg';
import DiceBlue05 from './assets/dice-blue-5.svg';
import DiceBlue06 from './assets/dice-blue-6.svg';
//Red 사진
import DiceRed01 from './assets/dice-red-1.svg';
import DiceRed02 from './assets/dice-red-2.svg';
import DiceRed03 from './assets/dice-red-3.svg';
import DiceRed04 from './assets/dice-red-4.svg';
import DiceRed05 from './assets/dice-red-5.svg';
import DiceRed06 from './assets/dice-red-6.svg';
● 순서2_ Blue / Red 냐에 따라 6개씩 나눠지고, 숫자 눈에 따라 다르므로, => 배열이 아닌, 객체로 미리 변수들을 저장한다.
const ImgSrcs = {
blue : [DiceBlue01, DiceBlue02, DiceBlue03, DiceBlue04, DiceBlue05, DiceBlue06],
//Blue 주사위 Img Src 보관
red : [DiceRed01, DiceRed02, DiceRed03, DiceRed04, DiceRed05, DiceRed06],
//Red 주사위 Img Src 보관
}
● 순서3_ <Dice>컴포넌트의 function 작성
○ props.color , props.num을 매개로 받아, 그 값에 따라 적절한 주사위 눈의 사진변수를 고를 수 있도록 한다.
function Dice({color, num}) {
const Src = ImgSrcs[color][num-1];
const Alt = `Dice-${color}_${num}`;
return <img src={Src} alt={Alt}/>;
}
export default Dice; //외부에서 Dice 컴포넌트를 사용할 수 있도록 함
//일단 버튼부터 만들어보자
◎ 4_ Button.js 작성 과정
● 순서1_"던지기", "처음부터"의 textContent의 버튼 만듪기 (기능은 아X) => props.Children 객체 프로퍼티 이용 //여기서 문제가 많이 발생함
//Button.js
function Button({children})//children인, props 객체 프로퍼티를 이용하여,
{
return (<button>{children}</button>); //컴포넌트 태그 TextContent에 바로 작성될 수 있도록 한다.
}
export default Button;
※ 문제_ React 최신버전만 children 객체가 가능했던것 같음
=> 해결방법 :
import React from 'react';//얘도 import 추가
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));//가장 상위 노드를 변수로 저장하고
root.render(<App/>);//그 상위 노드의 객체 프로퍼티 메소드인, render메소드 내 포함
● 순서2_ App.js에 <Button>컴포넌트 태그 2개 추가 //"던지기", "처음부터"
//App.js
import HeadImg from './assets/logo.png';
import Button from './Button';
function App() {
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div>
//childern객체 프로퍼티를 이용하여, 바로 태그 내에 텍스트를 출력할 수 있도록 한다.
<Button>던지기</Button>
<Button>처음부터</Button>
</div>
<div className='Board'>
</div>
</>
);
}
export default App;
● 순서3_ useState 메소드 사용
○ 기본적인 useState() 사용 공식 :
import { useState } from 'react'; //import로 useState 사용할 수 있도록 라이브러리 불러오기
const [조작할 변수, 조작할 수 있도록 하는 메소드] = useState(변수의 초기값);
//클릯했을 때, 핸들러에 useState 적용
//ex_ 버튼을 누를 시, 값이 1이 되도록 한다.
const handleClick = () => {
조작할 수 있도록 하는 메소드(2);
};
//버튼 태그에 적용
<button onClick = {handleClick}></button>
○ App.js에 "던지기" <Button> 컴포넌트와 Dice를 추가하여, "던지기" 버튼을 누를 시, 주사위 눈이 랜덤하게 바뀌는 작동 구현하기
//App.js
//1_ 필요한 import문 작성
import { useState } from 'react';//useState 사용을 위한 import문
import HeadImg from './assets/logo.png';
import Button from './Button';//<Button> 컴포넌트 태그 사용을 위한 import문
import Dice from './Dice';//<Dice> 컴포넌트 태그 사용을 위한 import문
//2_ 1~6 넌수 발생 메소드
function randNum()
{
return Math.floor(Math.random()*(6-0)) +1;
}
function App() {
//3. 주사위 눈에 대한 useState()
const [myNum, setMyNum] = useState(1);
//4. "던지기"버튼에 대한 핸들러 메소드
const handleRollClick = ()=>
{
setMyNum(randNum());
//버튼 누를 시myNum 변수값을 난수로 설정
};
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div>
//5. "던지기"버튼에 onClick 속성값에 핸들러 적용
<Button onClick={handleRollClick}>던지기</Button>
<Button>처음부터</Button>
</div>
<div className='Board'>
//6. 위에서 버튼 적용 후, 바뀐 myNum값을 num의 프로퍼티에 적용
<Dice color='blue' num={myNum}/>
</div>
</>
);
}
export default App;
○ 출력 장면 :
○ 이제 같은방식으로, "처음부터" 버튼도 추가로 적용
//App.js에서 추가된 부분
function App() {
//"처음부터" 버튼 누를 시 , 작동될 핸들러
const handleRollReset = () =>
{
setMyNum(1);//myNum값 1로 되올리도록 설정
}
<Button onClick={handleRollReset}>처음부터</Button>
//"처음부터" 버튼 태그에 onCLick속성값에 핸들러 적용
//..
}
○ 마지막으로 총점, 기록 적용
import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Dice from './Dice';
function randNum()//1~6 넌수 발생 메소드
{
return Math.floor(Math.random()*(6-0)) +1;
}
function App() {
//주사위 눈에 대한 useState()
const [myNum, setMyNum] = useState(1);//나
const [otherNum, setOtherNum] = useState(1);//상대
//배열 선언
const [myRecord,setMyRecord] = useState([]);
const [otherRecord,setOtherRecord] = useState([]);
//던지기에 대한 핸들러 메소드
const handleRollClick = ()=>
{
const blueNum = randNum();
const redNum = randNum();
//주사위 눈
setMyNum(blueNum);
setOtherNum(redNum);
// 기록 업데이트
setMyRecord((myRecord) => [...myRecord, blueNum]);
setOtherRecord((otherRecord) => [...otherRecord, redNum]);
};
const handleRollReset = () =>
{
//주사위 눈 1로 Reset
setMyNum(1);
setOtherNum(1);
//기록을 빈 배열로 초기화
setMyRecord([]);
setOtherRecord([]);
}
// 총점 계산 (렌더링 시 계산)
const mySum = myRecord.reduce((a, b) => a + b, 0);
const otherSum = otherRecord.reduce((a, b) => a + b, 0);
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleRollReset}>처음부터</Button>
</div>
<div className='Board'>
<Dice color='blue' num={myNum} record = {myRecord}/>
<h2>나의 총점</h2>
<p>{mySum}</p>
<h2>나의 기록</h2>
<p>{myRecord.join(", ")}</p>
<Dice color='red' num={otherNum} record = {otherRecord}/>
<h2>상대의 총점</h2>
<p>{otherSum}</p>
<h2>상대의 기록</h2>
<p>{otherRecord.join(", ")}</p>
</div>
</>
);
}
export default App;
◆ 여기서 내가 어려웠던 부분 :
- 요인1_ 핸들러에 배열 업데이트 방법 :
//"던지기" 버튼 누를 시, 작동될 핸들러
const handleRollClick = ()=>
{
//배열 업데이트 부분
setMyRecord((myRecord)=>[...MyRecord, 새로 추가할 값]);
}
- 요인2_ 총점의 값은 다 기록된 후의 합을 구하는 것이므로, 핸들러 코드 부분 ~ return 문 사이에 처리하는 것
function App() {
//"던지기" 버튼 누를 시, 작동될 핸들러
const handleRollClick = ()=>
{
//...생략
}
//"처음부터" 버튼 누를 시, 작동될 핸들러
const handleRollReset = () =>
{
//...생략
}
// 총점 계산 (렌더링 시 계산)
const mySum = myRecord.reduce((a, b) => a + b, 0);
const otherSum = otherRecord.reduce((a, b) => a + b, 0);
return (<>-</>)
}
그리고, 배열의 합을 변수의 저장하는 코드는 암기해두면, 좋다.
const Sum = 배열.reduce((a,b)=>a+b,0);
=> 설명 : 배열이 비어있다면, 초기값 0이고, 왼쪽 인덱스 순으로
0+a
a + b
b + 다음 인덱스 원소 ,. 로 누적합 계산
○ 최종 코드 (App.js)
import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Dice from './Dice';
function randNum()//1~6 넌수 발생 메소드
{
return Math.floor(Math.random()*(6-0)) +1;
}
function App() {
//주사위 눈에 대한 useState()
const [myNum, setMyNum] = useState(1);//나
const [otherNum, setOtherNum] = useState(1);//상대
//배열 선언
const [myRecord,setMyRecord] = useState([]);
const [otherRecord,setOtherRecord] = useState([]);
//던지기에 대한 핸들러 메소드
const handleRollClick = ()=>
{
const blueNum = randNum();
const redNum = randNum();
//주사위 눈
setMyNum(blueNum);
setOtherNum(redNum);
// 기록 업데이트
setMyRecord((myRecord) => [...myRecord, blueNum]);
setOtherRecord((otherRecord) => [...otherRecord, redNum]);
};
const handleRollReset = () =>
{
//주사위 눈 1로 Reset
setMyNum(1);
setOtherNum(1);
//기록을 빈 배열로 초기화
setMyRecord([]);
setOtherRecord([]);
}
// 총점 계산 (렌더링 시 계산)
const mySum = myRecord.reduce((a, b) => a + b, 0);
const otherSum = otherRecord.reduce((a, b) => a + b, 0);
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleRollReset}>처음부터</Button>
</div>
<div className='Board'>
<Dice color='blue' num={myNum} record = {myRecord}/>
<h2>나의 총점</h2>
<p>{mySum}</p>
<h2>나의 기록</h2>
<p>{myRecord.join(", ")}</p>
<Dice color='red' num={otherNum} record = {otherRecord}/>
<h2>상대의 총점</h2>
<p>{otherSum}</p>
<h2>상대의 기록</h2>
<p>{otherRecord.join(", ")}</p>
</div>
</>
);
}
export default App;
◎ 5_ [ Dice + 총점 +기록 ]을 <Board> 컴포넌트로 감싸기
● 순서1_ 전략짜기
○ Board 구조 :
//Board.js
//주사위 총점, 기록 안내 기록을 한 컴포넌트로 감싸기
import Dice from "./Dice";
function Board(){
return (
<>
<h2>{name}</h2>
<Dice color={color} num={num}></Dice>
<h2>{name}의 총점</h2>
<p>{sum}</p>
<h2>{name}의 기록</h2>
<p>{record.join(", ")}</p>
</>
);
}
○ Dice의 num, sum, record 처리 :
- App.js 에 Record를 useState를 한뒤, Board 컴포넌트에 전달한다.
- Board,.js에는 App.js에 버튼을 누른 뒤의 Record를 매개인자로 전달받아 , 마지막번째 나온 눈의 수 == num , 배열의 reduce 객체 프로퍼티 메소드로 합(Sum)을 처리한다.
- App.js
import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Board from './Board';
function randNum()//1~6 넌수 발생 메소드
{
return Math.floor(Math.random()*(6-0)) +1;
}
function App() {
//배열 선언
const [myRecord,setMyRecord] = useState([]);
const [otherRecord,setOtherRecord] = useState([]);
//던지기에 대한 핸들러 메소드
const handleRollClick = ()=>
{
const blueNum = randNum();
const redNum = randNum();
// 기록 업데이트
setMyRecord((myRecord) => [...myRecord, blueNum]);
setOtherRecord((otherRecord) => [...otherRecord, redNum]);
};
const handleRollReset = () =>
{
//기록을 빈 배열로 초기화
setMyRecord([]);
setOtherRecord([]);
}
return (
<>
<div className='Header'>
<img src={HeadImg} alt='head-logo-img'></img>
<h1>주사위 게임</h1>
</div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleRollReset}>처음부터</Button>
</div>
<div className='Board'>
<Board name="나" color="blue" record={myRecord}></Board>
<Board name="상대" color="red" record={otherRecord}></Board>
</div>
</>
);
}
export default App;
- Board.js
import Dice from "./Dice";
function Board({ name, color,record}) {
let num = 1;//초반 화면은 배열이 비어있으므로, default값 1로 처리
if(record.length>0)
{
num = record[record.length-1]//배열원소가 있다면, 배열 마지막 원소를 눈의 수로 한다.
}
const sum = record.reduce((a,b)=>a+b,0);
return (
<>
<h2>{name}</h2>
<Dice color={color} num={num}></Dice>
<h2>{name}의 총점</h2>
<p>{sum}</p>
<h2>{name}의 기록</h2>
<p>{record.join(", ")}</p>
</>
);
}
export default Board;
○ 출력 장면 :
'CodeIt_Sprint > React_초급' 카테고리의 다른 글
(18)React_초급_DiceGame_React_Project_2_인라인 작성부분 (0) | 2024.11.26 |
---|---|
(16)React_초급_React_배포하기 (0) | 2024.11.25 |
(15)React_초급_React_Design_최종 실습문제 2문제(이건 여러번 복습) (0) | 2024.11.25 |
(14)React_초급_React_Design_3_React에 CSS 적용하는 여러가지 방법 (0) | 2024.11.25 |
(13)React_초급_React_Design_2_외부CSS파일 불러오기 (0) | 2024.11.25 |