React

Vanilla JS 🆚 React JS

yunieyunie 2023. 4. 24. 21:29

Vanilla JS와 React JS로 click me 버튼을 클릭하면 total clicks의 수가 하나씩 증가하는 기능을 각각 만들어 비교해보자.

 

Vanilla JS

<body>
  <h3>total clicks : 0</h3>
  <button id="button">click me</button>
</body>
<script>
  const button = document.getElementById('button');
  const h3 = document.querySelector('h3');
  let counter = 0;

  function handleClick() {
  counter += 1;
  h3.innerText = `total clicks : ${counter}`;
  }

  button.addEventListener('click', handleClick);
</script>

 

Vanilla JS는 html을 만들고 js로 가져와서 다시 html을 수정하는 방식이다.

하지만 React JS는 처음부터 js에서 시작하여 html을 만들기에 html 코드를 직접 작성할 필요가 없다.

React JS로 element를 직접 생성할 수 있기 때문이다.

따라서 React JS는 html의 element를 바로 업데이트 할 수 있어 interactive application 을 만들기에 좋다.

또한 React JS는 UI에서 바뀐 부분만 업데이트 된다는 장점이 있다.

 

React JS - 1) createElement 

createElement를 사용하는 방법은 개발자들이 거의 사용하지 않는 방법이다.

좀 더 쉽고 생산적인 방법이 있기 때문이다.

하지만 먼저 이 방법을 이해해야 React JS의 본질을 이해할 수 있다.

React JS는 interactive의 원동력이며, React DOM은 React element 를 html로 바꿔준다.

 

<body>
  <div id="root"></div>
</body>
<script>
  let counter = 0;
  const root = document.getElementById('root');

  const handleClick = () => {
    counter += 1;
    render();// 클릭할 때마다 render() 함수를 호출하여 UI를 업데이트
  };

  const render = () => {
    const h3 = React.createElement('h3', null, `total clicks : ${counter}`);
    const button = React.createElement('button', {onClick: handleClick}, 'click me'); // onClick 속성에 handleClick 함수 전달
    const app = React.createElement('div', null, [h3, button]);

    ReactDOM.render(app, root);
  };

  render(); // 초기 UI 렌더링
</script>

 

React JS - 2) JSX

createElement를 대체하려는 이유는 개발자들에게 좀 더 편리한 JSX를 사용하기 위함이다.
JSX는 JS를 확장한 것으로 html 규칙과 비슷한 문법으로 React 요소를 생성할 수 있어 개발자들에게 더 편하다.
그런데 JSX로 적은 코드를 브라우저가 이해할 수 있게 1) 방법으로 바꿔주는 babel 이 필요하다.

 

<body>
  <div id="root"></div>
</body>

<script type="text/babel">
  const root = document.getElementById('root');
  let counter = 0;

  const handleClick = () => {
    counter += 1;
    render();// 클릭할 때마다 render() 함수를 호출하여 UI를 업데이트
  };

  const render = () => {
    ReactDOM.render(<App />, root);
  };

  const H3 = () => (
    <h3>total clicks : {counter}</h3>
  );

  const Button = () => (
    <button onClick={() => handleClick()}>click me</button>
  );

  const App = () => (
    <div>
      <H3 />
      <Button />
    </div>
  );

  render(); // 초기 UI 렌더링
</script>

 

여기서 꼭 체크해야할 매우 중요한 것은 컴포넌트의 첫문자는 항상 대문자로 시작해야만 한다는 것이다.

소문자로 한다면 html 태그로 인식하게 된다.

H3와 Button를 따로 함수로 만들지 않고 그냥 Container 안에 포함시킬 수도 있다.

 

<body>
  <div id="root"></div>
</body>

<script type="text/babel">
  const root = document.getElementById('root');
  let counter = 0;

  const handleClick = () => {
    counter += 1;
    render();// 클릭할 때마다 render() 함수를 호출하여 UI를 업데이트
  };

  const render = () => {
    ReactDOM.render(<App />, root);
  };
 
  const App = () => (
    <div>
      <h3>total clicks : {counter}</h3>
      <button onClick={() => handleClick()}>click me</button>
    </div>
  );

  render(); // 초기 UI 렌더링
</script>

 

그런데 이는 계속해서 App를 render 해주기 때문에 최고의 방법은 아니다.

어떤 페이지나 알림 등이 있는데 이를 계속 호출해야 되는 것은 비효율적이기 때문이다.

 

 

React JS - 3) useState

계속 함수를 부를 필요 없이 React JS 내에서 데이터를 보관하고 자동으로 rerendering 하는 방법이다.

const [현재값 state, state를 수정하는 modifier 함수] = React.useState(초기값);

state를 수정하는 함수는 보통 set+변수명 으로 설정한다.

 

<body>
    <div id="root"></div>
  </body>

  <script type="text/babel">
    const root = document.getElementById("root");
   
    function App (){
      const [counter, setCounter] = React.useState(0);
      const handleClick = () => {
        setCounter((cur) => cur + 1);
      };
      return(
        <div>
          <h3>total clicks : {counter}</h3>
          <button onClick={handleClick}>click me</button>
        </div>
      );
    }

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

 

modifier 함수가 state를 바꾸면 App component가 재생성되고 코드가 재실행되는데 이 때 return은 새로운 값을 가지고 재실행이 된다.

즉, state가 바뀌면 rerendering이 일어난다는 것이며, rerendering 될 때 React JS는 UI가 업데이트가 된 부분만 달라지게 한다.

여기서 handleClick 안의 setCounter를 다음과 같이 직접 할당 방법으로 수정해도 결과는 변함없다.

 

setCounter(counter +1);

 

하지만 이는 현재 state와 관련없는 값을 새로운 state로 하고 싶은 경우에 해당한다.

setState()는 component를 항상 즉각적으로 갱신하지 않기 때문에 예상치 못한 업데이트가 어딘가에서 일어난다면 잠재적인 문제가 될 수 있으므로 이전 state 값을 기준으로 state를 설정해야 한다면 직접 할당이 아닌 함수형으로 넣어주는 것이 더 안전하다.