본문 바로가기
CodeIt_Sprint/React_초급

(11)React_초급_ 컴포넌트 재사용 하기(작성중)

by 코잼민 2024. 11. 23.

● Defalut 상황

 

● 1단계 : Defalut의 App.js 컴포넌트를 Board컴포넌트로 수정한뒤, Board컴포넌트 2개(나, 상대)가 들어있는 App.js 적용 후, index.js에 <App> 컴포넌트만 사용해서 작동시켜보기

§ 해당 요구사항 출력 결과 :

§ 과정 :

 

● 2단계 : "던지기" 버튼 , "처음부터" 버튼 하나로, 2개의 주사위를 동시에 적용되도록 하기

§ 과정 :

○ 순서1_ App 컴포넌트에 useState 메소드를 가져와야 => Board.Blue 컴포넌트, Board.Red 컴포넌트를 동시에 다룰 버튼 적용 가능

 

function App() {

  //나의 패 데이터
  const [myNum,setMyNum] = useState(1);
  const [mySum,setMySum] = useState(0);
  const [myRecord,setMyRecord] = useState([]);

  //상대 패 데이터
  const [otherNum,setOtherNum] = useState(1);
  const [otherSum,setOtherSum] = useState(0);
  const [otherRecord,setOtherRecord] = useState([]);

  //onClick 메소드 : 던지기
  const handleRollClick = () =>{

    let randMyNum = Math.floor(Math.random()*(6-0)) +1;
    let randOtherNum = Math.floor(Math.random()*(6-0)) +1;
    
    //나의 패 적용
    setMyNum(randMyNum);
    setMySum(mySum + randMyNum);
    setMyRecord([...myRecord, randMyNum]);
    
    //상대편 패 적용
    setOtherNum(randOtherNum);
    setOtherSum(otherSum + randOtherNum);
    setOtherRecord([...otherRecord, randOtherNum]);

  }

  const setClear = ()=>{
        //나의 패 적용
        setMyNum(1);
        setMySum(0);
        setMyRecord([]);
        
        //상대편 패 적용
        setOtherNum(1);
        setOtherSum(0);
        setOtherRecord([]);
  }
  
  return (
    <>
    <div>
      <Button >던지기</Button>
      <Button >처음부터</Button>
    </div>
      <Board name="나" color="blue"/>
      <Board name="상대" color="red"/>
    </>
  )
  
  }

○ 순서2_App.js 내부 <Button> 컴포넌트에 [순서1]에서 선언한 useState와 onClick 메소드 적용하기

  return (
    <>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>//onClick의 주사위 눈 돌리는 메소드 적용\
        <Button onClick={setClear}>처음부터</Button>//onClikck의 Reset하는 메소드 적용
      </div>
      <Board name="나" color="blue"/>
      <Board name="상대" color="red"/>
    </>
  )

○ 순서3_App.js 내부 [순서1]에서 적용한 나의 주사위 눈 , 점수, 기록 && 상대의 주사위 눈, 점수 , 기록 <Board> 컴포넌트에 적용하기

①. ★<Button> 컴포넌트의 function의 props 객체의 프로퍼티 매개인자 추가 해서, 전달

- Board.js

import Dice from './Dice';

function Board({name , color, num, sum, Record}) {


  return (
    //.Array프로퍼티 메소드 join(', ')메소드를 이용하여, 배열에 원소 출력
    <>
      <h1>{name}</h1>
      <Dice color={color} num={num} />
      <p>총점 : {sum}</p> 
      <p>기록 : {Record.join(', ')}</p> 
    </>
  )
}

export default Board;

②. 다시, App.js에서 myNum, mySum,myRecord && otherNum, otherSum, otherRecord

- App.js의 function 일부

 return (
    <>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>
        <Button onClick={setClear}>처음부터</Button>
      </div>
      <Board name="나" color="blue" num={myNum} sum={mySum} Record={myRecord} />
      <Board name="상대" color="red" num={otherNum} sum={otherSum} Record={otherRecord} />
    </>
  )

§ 최종 코드 결과

◆ App.js :

import { useState } from "react";
import Button from "./Button";
import Board from "./Board";

function App() {

  //나의 패 데이터
  const [myNum, setMyNum] = useState(1);
  const [mySum, setMySum] = useState(0);
  const [myRecord, setMyRecord] = useState([]);

  //상대 패 데이터
  const [otherNum, setOtherNum] = useState(1);
  const [otherSum, setOtherSum] = useState(0);
  const [otherRecord, setOtherRecord] = useState([]);

  //onClick 메소드 : 던지기
  const handleRollClick = () => {

    let randMyNum = Math.floor(Math.random() * (6 - 0)) + 1;
    let randOtherNum = Math.floor(Math.random() * (6 - 0)) + 1;

    //나의 패 적용
    setMyNum(randMyNum);
    setMySum(mySum + randMyNum);
    setMyRecord([...myRecord, randMyNum]);

    //상대편 패 적용
    setOtherNum(randOtherNum);
    setOtherSum(otherSum + randOtherNum);
    setOtherRecord([...otherRecord, randOtherNum]);

  }

  const setClear = () => {
    //나의 패 적용
    setMyNum(1);
    setMySum(0);
    setMyRecord([]);

    //상대편 패 적용
    setOtherNum(1);
    setOtherSum(0);
    setOtherRecord([]);
  }


  return (
    <>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>
        <Button onClick={setClear}>처음부터</Button>
      </div>
      <Board name="나" color="blue" num={myNum} sum={mySum} Record={myRecord} />
      <Board name="상대" color="red" num={otherNum} sum={otherSum} Record={otherRecord} />
    </>
  )
}

export default App;

◆ Board.js :

import Dice from './Dice';

function Board({name , color, num, sum, Record}) {


  return (
    //.Array프로퍼티 메소드 join(', ')메소드를 이용하여, 배열에 원소 출력
    <>
      <h1>{name}</h1>
      <Dice color={color} num={num} />
      <p>총점 : {sum}</p> 
      <p>기록 : {Record.join(', ')}</p> 
    </>
  )
}

export default Board;

◆ Button.js :


function Button(
  {children, onClick}
)
{
  return <button onClick={onClick}>{children}</button>
}

export default Button;

 

§ 해당 요구사항 출력 결과 :

 

※ 참고_저렇게 State메소드들을 App에 전부 처리하는 것을 StateLifting이라 한다네요 // 협업에서 쓰이는 용어랍디다.

● React 프로젝트의 보편적인 구조 :

○ App.js :

- state 구현

- 전체적인 틀 (html 부분)

  Button , Dice  : 사진, state에서 주고받는 props.속성을 작성

 

● 전체적인 코드 정리하기 :

  목표 : 굳이 num sum 없이, record배열만으로 작성 정리 해보기

App.js 코드 :

import { useState } from "react";
import Button from "./Button";
import Board from "./Board";

function App() {

  //나의 패 데이터
  const [myRecord, setMyRecord] = useState([]);

  //상대 패 데이터
  const [otherRecord, setOtherRecord] = useState([]);

  //onClick 메소드 : 던지기
  const handleRollClick = () => {

    let randMyNum = Math.floor(Math.random() * (6 - 0)) + 1;
    let randOtherNum = Math.floor(Math.random() * (6 - 0)) + 1;

    //나의 패 적용
    setMyRecord([...myRecord, randMyNum]);

    //상대편 패 적용
    setOtherRecord([...otherRecord, randOtherNum]);

  }

  const setClear = () => {
    //나의 패 적용
    setMyRecord([]);

    //상대편 패 적용
    setOtherRecord([]);
  }


  return (
    <>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>
        <Button onClick={setClear}>처음부터</Button>
      </div>
      <Board name="나" color="blue" Record={myRecord} />
      <Board name="상대" color="red" Record={otherRecord} />
    </>
  )
}

export default App;

 

Board.js 코드 :


import Dice from './Dice';

function Board({name , color, Record}) {
  const num = Record[Record.length-1]||1;
  let sum =Record.reduce((a,b)=>a+b,0);

  return (
    //.Array프로퍼티 메소드 join(', ')메소드를 이용하여, 배열에 원소 출력
    <>
      <h1>{name}</h1>
      <Dice color={color} num={num} />
      <p>총점 : {sum}</p> 
      <p>기록 : {Record.join(', ')}</p> 
    </>
  )
}

export default Board;

※  Board.js에서 num, sum 계산 부분 설명 :

1. const num = Record[Record.length - 1] || 1;

코드 분석

  • Record[Record.length - 1]:
    • 배열 Record의 마지막 요소를 가져옵니다.
    • Record.length - 1은 배열의 마지막 인덱스를 나타냅니다. 예를 들어:
      const Record = [3, 5, 6];
      const lastElement = Record[Record.length - 1]; // 6
      
    • 만약 배열이 비어 있다면(Record.length === 0), Record[Record.length - 1]는 undefined를 반환합니다.
  • || 1:
    • **OR 연산자 (||)**는 단락 평가(short-circuit evaluation)를 사용합니다.
    • Record[Record.length - 1]가 Falsy 값(undefined, null, 0, false, NaN, '')일 경우, **대체 값인 1**을 사용합니다.
    • 예를 들어:
      const Record = []; 
      const num = Record[Record.length - 1] || 1; // undefined || 1 -> num은 1
      

결론

num 변수에는 Record 배열의 마지막 요소가 저장됩니다. 배열이 비어 있다면 기본값 1이 저장됩니다.


2. let sum = Record.reduce((a, b) => a + b, 0);

코드 분석

  • Record.reduce(callback, initialValue):
    • reduce 메서드는 배열의 요소를 누적하여 단일 값으로 줄입니다.
    • 첫 번째 인수로 전달되는 callback 함수가 배열의 각 요소에 대해 실행됩니다.
    • 두 번째 인수인 **initialValue**는 누적값의 초기값으로 사용됩니다.

콜백 함수 (a, b) => a + b

  • a는 누적값(accumulator), b는 **현재 요소(current element)**를 나타냅니다.
  • 각 요소를 누적값에 더하여 총합을 계산합니다.

initialValue

  • 초기값으로 0이 설정되어 있습니다. reduce가 시작될 때 누적값(a)은 0부터 시작합니다.

예제

const Record = [3, 5, 6];
let sum = Record.reduce((a, b) => a + b, 0); // 초기값 0

// 연산 과정:
// 첫 번째 요소: 0 + 3 = 3
// 두 번째 요소: 3 + 5 = 8
// 세 번째 요소: 8 + 6 = 14

console.log(sum); // 14

이 코드가 하는 일

  • const num = Record[Record.length - 1] || 1;:
    • 배열 Record의 마지막 숫자를 가져옵니다. 배열이 비어 있다면 1을 사용합니다.
  • let sum = Record.reduce((a, b) => a + b, 0);:
    • Record 배열의 모든 요소를 합산하여 sum 변수에 저장합니다.

관련 코드 동작 예제

// 예제 1: 배열에 값이 있을 때
let Record = [2, 4, 6];
let num = Record[Record.length - 1] || 1; // 마지막 요소인 6
let sum = Record.reduce((a, b) => a + b, 0); // 총합: 2 + 4 + 6 = 12

console.log(`마지막 값: ${num}, 총합: ${sum}`); // 마지막 값: 6, 총합: 12

// 예제 2: 배열이 비어 있을 때
Record = [];
num = Record[Record.length - 1] || 1; // undefined || 1 -> num은 1
sum = Record.reduce((a, b) => a + b, 0); // 초기값 0 (요소가 없으므로)

console.log(`마지막 값: ${num}, 총합: ${sum}`); // 마지막 값: 1, 총합: 0

추가 참고

  1. **OR 연산자 (||)**는 Falsy 값 처리에 유용합니다.
    • Falsy 값: undefined, null, 0, false, NaN, ''.
    • Truthy 값은 그대로 사용됩니다.
  2. reduce 초기값은 필수적:
    • 배열이 비어 있으면 초기값이 없을 경우 TypeError가 발생할 수 있습니다.