FRONT-END/ReactJS Clone project

[노마드/ReactJS 영화 웹 만들기] - Ch03 | 0. State?

서근 2023. 1. 15. 18:10
반응형

ReactJS State

바닐라 JS에서 버튼을 클릭하면 Count가 올라가는 함수를 이벤트 리스너와 함께 구현하면 다음과 같다.

    <body>
        <span>클릭된 숫자: 0</span>
        <button id="btn">클릭</button>
    </body>
    <script>
        let count = 0;
        let span = document.querySelector('span');
        const btn = document.getElementById('btn');
        function handleClick() {
            console.log('클릭');
            count = count + 1;
            span.innerText = `클릭된 숫자: ${count}`;
        }
        btn.addEventListener('click', handleClick);
    </script>

바닐라 JS와 ReactJS는 값이 변경될 때 UI가 어떻게 rerender 되는지 확연하게 구분된다.

 

ReactJS는 UI에서 바뀐 부분만 업데이트해주고,

바닐라 JS는 변경된 태그 전체를 업데이트한다.

ReactJS로 변환

위 바닐라 JS코드를 ReactJS로 변환해 보자면

<!--ReactJS 구현부-->
<script type="text/babel">
    const root = document.getElementById('root');

    let counter = 0;

    function countUp() {
        counter = counter + 1;
        console.log(counter);
    }

    const Container = () => (
        <div>
            <h3 id="main-title">클릭 횟수: {counter}</h3>
            <button id="new-btn" onClick={countUp}>
                카운트 올리기
            </button>
        </div>
    );

    ReactDOM.render(<Container />, root);
</script>

오류 확인

하지만 버튼을 클릭하면, 클릭 이벤트는 정상적으로 작동하지만 UI에 반영되지는 않는다.

 

웹 페이지가 처음 실행되면 Container은 함수이기 때문에 바로 실행되지는 않고, 페이지가 로드되면서 Container 컴포넌트가 딱 한 번 랜더링 된다.

 

이벤트 리스너를 등록하고 클릭하면 conutUP 함수가 실행되지만, 최초로 Container를 랜더링 하고 더 이상 rerender 해주지 않았기 때문에 UI가 업데이트되지 않는 것이다.

해결 방법

이를 해결하기 위해서는 conutUP 함수가 실행될 때마다 Container 컴포넌트를 rerender 해줘야 한다.

function countUp() {
            counter = counter + 1;
            console.log(counter);
            ReactDOM.render(<Container />, root);
        }

랜더링 순서

  • 애플리케이션 실행 ➜
  • ReactDOM 랜더
  • counter = 0
  • 버튼 클릭 ➜
  • 함수 실행 (countUp())
  • ReactDOM re-render

랜더링 함수 생성

그렇다면 ReactDOM.render(<Container />, root); 는 사주 사용할 거 같기 때문에 함수로 만들어 주면 더 깔끔하고 재사용이 쉬워진다.

function countUp() {
            counter = counter + 1;
            console.log(counter);
            render();
        }

        function render() {
            ReactDOM.render(<Container />, root);
        }
        
//ReactDOM.render(<Container />, root); ➜
render()
더보기
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <div id="root"></div>
    </body>
    <script crossorigin src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
    <!--Babel 스크립트-->
    <script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <!--ReactJS 구현부-->
    <script type="text/babel">
        const root = document.getElementById('root');

        let counter = 0;

        function countUp() {
            counter = counter + 1;
            console.log(counter);
            render();
        }

        function render() {
            ReactDOM.render(<Container />, root);
        }

        const Container = () => (
            <div>
                <h3 id="main-title">클릭 횟수: {counter}</h3>
                <button id="new-btn" onClick={countUp}>
                    카운트 올리기
                </button>
            </div>
        );

        render();
    </script>
</html>

TIP
 
 

하지만! render 함수를 만들어 사용하는 방법이 최고의 방법은 아니다! 더 쉬운 방법이 있는데 왜냐하면 값이 바뀔 때마다 render() 함수를 넣어줄 순 없는 노릇이기 때문이다. 다음 포스트에서 이것을 어떻게 개선해 나아갈지 알아보자

React18 버전

React 18 버전부터는 createRoot를 사용해야 한다. 우선 Container를 전역에서 한번, 버튼 클릭할 때마다 rendering을 해야 하는데ReactDOMClient.createRoot(root).render()를 두 곳에 모두 쓸 경우와 function render()를 호출한 경우 모두 작동은 되지만 console창에 ReactDOMClient.createRoot() 대신 root.render()를 호출하라고 뜨게 된다.

 

React18부터는 ReactDOMClient.createRoot()를 변수에 담아 사용해야 한다.

 

const root = ReactDOM.createRoot(document.getElementById("root")); 라고 root 변수를 만들어 주고, render 함수를 만들지 않은 상태로 렌더링이 필요한 부분에 root.render(); 로 명명해 주면 된다.

더보기
const root = ReactDOM.createRoot(document.getElementById('root'));
let counter = 0;

function countUp() {
    counter++;
    Render();
}

function Render() {
    return root.render(<Container />);
}

const Container = () => (
    <div>
        <h3 id="main-title">클릭 횟수: {counter}</h3>
        <button id="new-btn" onClick={countUp}>
            카운트 올리기
        </button>
    </div>
);
Render();

 

깃허브 자료
 

GitHub - Seogun95/Movie-web-servic-ReactJS: ReactJS로 영화 웹 서비스 만들기 노마드 코더 클론 코딩

ReactJS로 영화 웹 서비스 만들기 노마드 코더 클론 코딩. Contribute to Seogun95/Movie-web-servic-ReactJS development by creating an account on GitHub.

github.com