본문 바로가기

React

React - component and props

React Element

root.render(<h1>안녕 리액트!</h1>);

위 코드는 아래와 같이 수정이 가능하다.

const element = <h1>안녕 리액트!</h1>;
root.render(element);

그리고 element변수를 console에 찍어보면 자바스크립트 객체가 출력되는 것을 확인할 수 있다.

이 객체를 'React Element'라고 부른다.

 

React Element를 render메서드에 전달하면, render메서드는 객체를 해석해서 HTML코드로 렌더링 시켜주는 것이다.

React Element는 화면을 구성하는데 있어서 기본적이며 핵심적인 요소이다.


React Component

React Element를 함수형태로 만들면 jsx문법 작성시 커스텀 태그처럼 활용이 가능하다.

import ReactDOM from 'react-dom/client';

function Hello() {
    return <h1>안녕 리액트!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
    <>
        <Hello/>
        <Hello/>
        <Hello/>
    </>);
  • 위 코드에서는 React Element를 반환하는 함수 'Hello()'를 태그처럼 사용하고 있는 모습을 볼 수 있다.
  • 이 때, 이 Hello 라는 함수를 'React Component'라고 부른다.
  • 본격적인 react개발을 할 때에는 React Component를 많이 사용하게 될 것이다.

React Component의 조건

  1. 함수 이름의 첫 글자는 대문자로 작성할 것.
  2. 반드시 jsx문법으로 만든 React Element를 반환할 것.

Component를 분리하면 좋은 점

리액트 개발을 컴포넌트 개발이라고 부를 수도 있지만, 컴포넌트는 리액트에서만 사용하는 것이 아니다.

컴포넌트는 '부품'을 의미하는 것이다.

이 세상 물건들을 부품으로 만들면 좋은 점은 아래와 같다.

  1. 반복적인 일이 줄어든다.(부품의 재사용이 가능하기 때문에)
  2. 고장을 고치기 쉽다.(고장난 부품만 고치면 되기 때문에)
  3. 일을 쉽게 나눌 수 있다.(여러 곳에서 만든 후 조립만 하면 되기 때문에)

마찬가지로 웹사이트에서도 컴포넌트를 만들면 아래와 같은 장점이 있다.

  1. 반복적인 개발이 줄어든다.
  2. 오류를 고치기 쉽다.
  3. 협업이 쉽다.

Component 재사용하기

// Boadr.js
import Dice from "./Dice";

function Board({name, color, num, sum, gameHistory}){
    return (
        <div>
            <h2>{name}</h2>
            <Dice color={color} num={num}/>
            <h2>총점</h2>
            <p>{sum}</p>
            <h2>기록</h2>
            <p>{gameHistory.join(', ')}</p>
        </div>
    );
}
export default Board;
/App.js
import {useState} from "react";
import Board from "./Board";
import Button from "./Button";

function random(n) {
    return Math.ceil(Math.random() * n);
}
function App(){
    const [num, setNum] = useState(1);
    const [sum, setSum] = useState(0);
    const [gameHistory, setGameHistory] = useState([]);

    const [otherNum, setOtherNum] = useState(1);
    const [otherSum, setOtherSum] = useState(0);
    const [otherGameHistory, setOtherGameHistory] = useState([]);

    const handleRollClick = () => {
        const nextNum = random(6);
        const nextOtherNum = random(6);
        setNum(nextNum);
        setSum(sum + nextNum);
        setGameHistory([...gameHistory, nextNum]);

        setOtherNum(nextOtherNum);
        setOtherSum(sum + nextOtherNum);
        setOtherGameHistory([...otherGameHistory, nextOtherNum]);
    }
    const handleClearClick = () => {
        setNum(1);
        setSum(0);
        setGameHistory([]);

        setOtherNum(1);
        setOtherSum(0);
        setOtherGameHistory([]);
    }

    return (
        <div>
            <div>
                <Button onClick={handleRollClick}>던지기</Button>
                <Button onClick={handleClearClick}>처음부터</Button>
            </div>
            <div>
                <Board name={"나"} color={"blue"} num={num} sum={sum} gameHistory={gameHistory}/>
                <Board name={"상대"} color={"red"} num={otherNum} sum={otherSum} gameHistory={otherGameHistory}/>
            </div>
        </div>
    );
}
export default App;
  • 위 코드에서는, 자식컴포넌트(Board.js)에서 사용할 num, sum, gameHistory 등을 부모컴포넌트(App.js)쪽에서 가지고있고, prop으로 전달해주고 있는 모습을 볼 수 있다.
  • 자식컴포넌트에서 사용하는 state를 부모쪽으로 끌러올려 사용하는 것을 state lifting 이라고 한다.
  • 동일한 변경사항을 여러 컴포넌트에 반영해야 할 필요가 있을때 사용한다.
  • 동일한 변경사항을 가져야하는 두 컴포넌트의 가장 가까운 공통조상으로 state를 올리면 된다.

Props

React Component에 속성을 지정하는 방법을 살펴보자.

import Dice from "./Dice";

function App(){
    return (
        <div>
            <Dice color="blue"/>
        </div>
    );
}
export default App;

위 코드를 실행 후, 개발자모드의 element를 보면, 아무것도 뜨지 않는다.

왜냐면 component에 props를 설정한 것이기 때문이다.

따라서 element탭이 아닌, react components탭을 봐야한다.

개발자모드를 직접 확인해보면, 우측의 props칸에 [ color: "blue" ] 를 확인할 수 있다.

 

props는 properties 의 줄임말이기때문에 컴포넌트에 전달된 모든 값들을 props라고 부르고,

각각의 속성은 prop이라고 부른다.

 

prop을 받아서 사용하는 방법

컴포넌트 태그에 지정된 prop은 하나의 객체형태로, 컴포넌트 함수의 첫번째 파라미터로 전달된다.

import diceblue01 from './assets/dice-blue-1.svg';

function Dice(props) {
    console.log(props);
    return <img src={diceblue01} alt='주사위' />;
}

export default Dice;
  • 위 코드를 실행해보면, props가 객체형태로 잘 넘어온 것을 확인할 수 있다.
  • 함수의 파라미터로 받는 props의 변수는 현재 "props" 로 받고있는데, 다른 이름으로 받아도 되지만 프롭을 받아오는 파라미터라는 의미를 전달하기 위해서 "props"로 짓는 경우가 많다고 한다.
  • prop은 렌더링 할 때의 화면을 상황에 따라 다르게 그리는 기능을 할 수 있다.

prop을 받아서 destructuring 문법을 사용해보자

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';
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';

const DICE_IMAGES = {
    blue: [diceBlue01, diceBlue02, diceBlue03, diceBlue04, diceBlue05, diceBlue06],
    red: [diceRed01, diceRed02, diceRed03, diceRed04, diceRed05, diceRed06]
};

function Dice(props) {
    const src = DICE_IMAGES[props.color][props.num-1];
    const alt = `${props.color} ${props.num}`;
    return <img src={src} alt={alt}/>;
}

export default Dice;

위 코드를 보면, Dice() 함수 내부에, props파라미터에서 '.'을 찍고 안에 있는 prop을 꺼내 쓰고 있는 것을 볼 수 있다.

이 경우, destructuring문법을 사용하여 조금 더 깔끔하게 작성할 수 있는데, 아래와 같다.

function Dice({color, num}) {
    const src = DICE_IMAGES[color][num-1];
    const alt = `${color} ${num}`;
    return <img src={src} alt={alt}/>;
}

children prop

  • 위에선 커스텀 prop을 사용했지만, 리액트에는 사실 기본 prop이 있다.
  • 컴포넌트의 자식들을 값으로 갖는 children prop이다.
  • react에서 단순히 보여지기만 하는 값을 다룰 때에는 prop을 직접 만들기보다는, children prop을 사용하는 편이 코드를 직관적으로 구성하는데 도움이 된다.

아래는 커스텀 prop을 사용해 작성된 코드이다.

// App.js
import Button from "./Button";


function App(){
    return (
            <div>
                <Button text="처음부터"/>
            </div>
    );
}
export default App;

// Button.js
function Button({text}){
    return <button>{text}</button>;
}

export default Button;

text라는 prop을 만들어서 Button 컴포넌트로 보내고 있다.

위 코드를 children prop을 사용하는 것으로 바꾸면 아래와 같다.

// App.js
import Button from "./Button";


function App(){
    return (
            <div>
                <Button>처음부터</Button>
            </div>
    );
}
export default App;

// Button.js
function Button({children}){
    return <button>{children}</button>;
}

export default Button;
  • prop을 아무것도 보내고있지 않으나, Button컴포넌트에서 파라미터로 children prop을 받고 있다.
  • children prop은 html태그의 사이에 들어있는 값이다.
  • 위 예시처럼 단순 문자열이 될 수도있고, 다른 컴포넌트나 다른 HTML태그가 될 수도 있다.