본문 바로가기

Front End/React

[React Exam 35] Counter 만들어보기

순수 자바스크립트로 만들어 보자!!!

Counter01.html 파일을 만들자!!

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>순수 자바스크립트인 바닐라 JS 카운터</title>
</head>
<body>
    <div class="btn-group btn-group-sm" role="group" style="border: 1px solid gray;margin: 5px;" >
        <button type="button" class="btn btn-secondary" id="decrease1">-</button>
        <button type="button" class="btn btn-light" id="counter1">0</button>
        <button type="button" class="btn btn-secondary" id="increase1">+</button>
    </div>
    <script>
        const counter1 = document.querySelector("#counter1");
        document.querySelector("#decrease1").onclick = ()=>{
            counter1.innerText = counter1.innerText * 1 - 1;
        }
        document.querySelector("#increase1").onclick = ()=>{
            counter1.innerText = counter1.innerText * 1 + 1;
        }
    </script>
</body>
</html>

 

잘 작동한다.

 

이번에는 리액트로 만들어 보자!!

 

Counter.js 파일을 만들자

import Button from 'react-bootstrap/Button';
import ButtonGroup from 'react-bootstrap/ButtonGroup';
import 'bootstrap/dist/css/bootstrap.min.css';
import { useState } from 'react';

const Counter = () => {
    const [counter, setCounter] = useState(0);

    const increaseHandler = () => {
        setCounter(prevCount => prevCount + 1);
    };
    const decreaseHandler = () => {
        setCounter(prevCount => prevCount - 1);
    };
    return (
        <ButtonGroup style={{ border: "1px solid gray", margin : "5px" }} size="sm">
            <Button variant="secondary" onClick={decreaseHandler}> - </Button>
            <Button variant="light"> {counter} </Button>
            <Button variant="secondary" onClick={increaseHandler}> + </Button>
        </ButtonGroup>
    );
}
export default Counter;

 

App.js 파일을 만들자

import Counter from "./Counter";
const App = ()=>{
    return (
        <>
            <Counter/>
        </>
    );
}
export default App;
 

index.js 파일을 만들자

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
    <React.StrictMode>
        <App/>
    </React.StrictMode>
);  

 

실행 결과 입니다.

 

위의 두 개 결과를 비교해 보자.

순수 JavaScript를 사용해서 만든것이 더 간단해 보인다.

그런데 카운터가 여러개 필요하다고 생각해 보자!!!!

 

그렇다면 html파일은 다은과 같이 변경 되어야 한다.

카운터 개수만큼 태그를 추가하고 javaScript 코드도 추가해 주어야 한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>순수 자바스크립트인 바닐라 JS 카운터</title>
</head>
<body>
    <div class="btn-group btn-group-sm" role="group" style="border: 1px solid gray;margin: 5px;" >
        <button type="button" class="btn btn-secondary" id="decrease1">-</button>
        <button type="button" class="btn btn-light" id="counter1">0</button>
        <button type="button" class="btn btn-secondary" id="increase1">+</button>
    </div>
    <script>
        const counter1 = document.querySelector("#counter1");
        document.querySelector("#decrease1").onclick = ()=>{
            counter1.innerText = counter1.innerText * 1 - 1;
        }
        document.querySelector("#increase1").onclick = ()=>{
            counter1.innerText = counter1.innerText * 1 + 1;
        }
    </script>

    <div class="btn-group btn-group-sm" role="group" style="border: 1px solid gray;margin: 5px;" >
        <button type="button" class="btn btn-secondary" id="decrease2">-</button>
        <button type="button" class="btn btn-light" id="counter2">0</button>
        <button type="button" class="btn btn-secondary" id="increase2">+</button>
    </div>
    <script>
        const counter2 = document.querySelector("#counter2");
        document.querySelector("#decrease2").onclick = ()=>{
            counter2.innerText = counter2.innerText * 1 - 1;
        }
        document.querySelector("#increase2").onclick = ()=>{
            counter2.innerText = counter2.innerText * 1 + 1;
        }
    </script>

    <div class="btn-group btn-group-sm" role="group" style="border: 1px solid gray;margin: 5px;" >
        <button type="button" class="btn btn-secondary" id="decrease3">-</button>
        <button type="button" class="btn btn-light" id="counter3">0</button>
        <button type="button" class="btn btn-secondary" id="increase3">+</button>
    </div>
    <script>
        const counter3 = document.querySelector("#counter3");
        document.querySelector("#decrease3").onclick = ()=>{
            counter3.innerText = counter3.innerText * 1 - 1;
        }
        document.querySelector("#increase3").onclick = ()=>{
            counter3.innerText = counter3.innerText * 1 + 1;
        }
    </script>
</body>
</html>

 

실행결과입니다. 나름 고생은 했지만 잘 작동한다.

 

그렇다면 리액트로 만든것을 사용한다면 어떻게 해야 할까?

App.js파일만 다음과 같이 수정한다.

import Counter from "./Counter";
const App = ()=>{
    return (
        <>
            <Counter/>
            <Counter/>
            <Counter/>
        </>
    );
}
export default App;

 

실행결과입니다. 

 

어떤것을 선택할까는 사용자에게 선택의 기회를 드리도록 하지요!!

 

이렇게 가능한것은 Component가 고유의 상태값을 가지고 있기 때문입니다.

코드를 보면 아래의 코드가 보입니다. useState()라는 코드가 보입니다. 

const [counter, setCounter] = useState(0);

 

여기서 useState가 바로 Hook 입니다. Hook에 대해서는 다음 포스트부터 자세하게 알아보도록 하겠습니다.

Hook을 호출해 함수 컴포넌트(function component) 안에 state를 추가했습니다. 이 state는 컴포넌트가 다시 렌더링 되어도 그대로 유지될 것입니다.

useState는 현재의 state 값과 이 값을 업데이트하는 함수를 쌍으로 제공합니다.


const [변수명, 변수명에 값을 변경할 함수이름] = useState(초기값);

 

여기서 변수명과 Setter함수명의 이름은 마음대로 지정할 수 있습니다. 보통의 경우 다음과 같이 사용합니다.

  // 여러 개의 state를 선언할 수 있습니다!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

 

counter라는 상태 변수를 만들고 setCounter()함수로 counter값을 변경하면 알아서 상태값의 변경을 감지하고 리렌더링을 수행합니다.

 

이렇게 상태 값을 선언하면 컴포넌트 마다 고유한 변수를 가지므로 충돌이 일어 날 일이 없습니다. 그래서 컴포넌트를 추가만 하면 자동으로 작동하는것입니다.