본문 바로가기
Frontend/React

React, JSX, Virtual DOM 기본 개념과 문법

by 신림쥐 2024. 1. 3.
728x90

 

     


    React

    가장 작은 React 예제는 다음과 같습니다.

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<h1>Hello, world!</h1>);

     

    풀어서 말하면,

    • 프로젝트 규모가 커지고, 다양한 유저 인터렉션이 전달되면서 DOM요소의 변화가 많아지게 되면서 DOM 요소의 변화를 개발자가 직접 관리하는 어려움을 개선하기 위해 DOM 관리와 상태 변화 관리를 최소화하고, 개발자 오직 기능 개발, 사용자 인터페이스에 더 집중할수 있게 만들어진 프론트앤드 라이브러리, 프레임워크중 하나 이다.
    • 리액트에서는 컴포넌트 단위로 작성하여 하나의 컴포넌트를 여러 부분에서 재사용하여 생산성과 유지보수에 좋다.
    • Virtual DOM을 사용하여 렌더링 효율성이 높다.

     

    React가 인기있는 이유는 무엇일까?

    • 기술 쏠림 현상을 가지고 있는 대한민국 IT문화상 Virtual DOM을 토대로한 장점으로 초기 독점을 하였고, 현재까지 유지되어 사용율 1위를 차지하고 있다.
    • 2024년 기준 리액트를 대신할 수 있는 프레임워크가 나오지 않는 이상 아마 트랜드가 유지될것으로 전망된다.

     

    React 가치관

    선언적

    React는 대화형 UI를 만드는 것을 고통스럽지 않게 만듭니다. 애플리케이션의 각 상태에 대한 간단한 뷰를 디자인하면 React는 데이터가 변경될 때 적절한 구성 요소만 효율적으로 업데이트하고 렌더링합니다.

    선언적 뷰를 사용하면 코드를 더 예측 가능하고 디버깅하기가 더 쉬워집니다.

    구성 요소 기반

    자체 상태를 관리하는 캡슐화된 구성요소를 구축한 다음 이를 구성하여 복잡한 UI를 만듭니다.

    구성 요소 로직은 템플릿 대신 JavaScript로 작성되므로 앱을 통해 풍부한 데이터를 쉽게 전달하고 DOM에서 상태를 유지할 수 있습니다.

    한번 배우고, 어디서든 쓸 수 있다

    우리는 나머지 기술 스택에 대해 가정하지 않으므로 기존 코드를 다시 작성하지 않고도 React에서 새로운 기능을 개발할 수 있습니다.

    React는 Node를 사용하여 서버에서 렌더링할 수도 있고 React Native를 사용하여 모바일 앱에서도 렌더링할 수 있습니다 .

     

    왜 JSX인가?

    React는 렌더링 로직이 다른 UI 로직, 즉 이벤트 처리 방법, 시간이 지남에 따라 상태가 변경되는 방법, 데이터가 표시를 위해 준비되는 방법과 본질적으로 결합되어 있다는 사실을 수용합니다.

    React는 마크업과 로직을 별도의 파일에 넣어 인위적으로 기술을 분리하는 대신 , 둘 다 포함하는 느슨하게 결합된 단위인 "컴포넌트"로 관심사를 분리합니다 . 다음 섹션 에서 컴포넌트로 돌아가겠지만 , 아직 JS에 마크업을 넣는 데 익숙하지 않다면 이 강연이 설득력이 있을 수 있습니다.

    React는 JSX를 사용할 필요가 없지만 , 대부분 사람들은 JavaScript 코드 내에서 UI를 작업할 때 시각적 보조 도구로 유용하다고 생각합니다. 또한 React가 더 유용한 오류 및 경고 메시지를 표시할 수 있습니다.

    이제 시작해볼까요!

    const element = <h1>Hello, world!</h1>;

    위에서 본 마크업 구문은 JSX 라고 합니다 .
    선택 사항이지만 대부분의 React 프로젝트는 편의를 위해 JSX를 사용합니다. 로컬 개발에 권장하는 모든 도구는 JSX를 기본적으로 지원합니다.

     

     

    JSX(JavaScript XML)란?

    • JSX는 JavaScript XML의 약자
    • Javascript 에서 XML을 추가하여 자바스크립트에서 HTML 문법을 사용할 수 있게 해주는 Javascript를 확장한 문법이다.
    • 리액트 및 React기반 프레임워크(Next.js, Gatsby, Remix 등)에서 사용하는 방식이며 다른 프레임워크나 라이브러리에서도 옵션 등으로 존재한다.

    다시 말해서, 

    • JS보다 직관성, 가독성이 좋은 HTML을 이용하여 만들어진 자바스크립트에 대한 확장 구문
    • 익숙한 HTML 문법과 유사한 JSX를 통해 컴포넌트 단위로 분리는 생성되는 렌더링 방식 지원
    • 마크업 코드에 익숙하다면 그것만으로도 JSX를 통해 컴포넌트를 구성하는데 쉽게 적응할 수 있다.
    • 리액트에서 요소를 제공하여 사용되며 리액트에서 JSX 사용이 필수가 아니지만, JS안에서의 JSX는 렌더링에 도움을 준다. 렌더링 마다 HTML 태그를 createElement 사용하지 않아도, JS를 통해 ui 렌더링이 편안하게 변경되어 주로 같이 사용한다.

     

    JSX가 웹사이트에 어떻게 그려지나요?

    • JSX 코드는 Babel이 트랜스파일링되어 html 태그가 아니라 자바스트립트 변환되어 화면을 그린다.
    • 즉 브라우저 실행 전 코드가 번들링 되면서 컴파일 후 JSX 표현식이 정규 JavaScript 함수 호출이 되고 JavaScript 객체로 인식되는 코드
    // JSX
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    
    // JS로 변환된 JSX
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    // JSX
    function App() {
    	return (
        	<div>
            	Hello <b>react</b>
            </div>
        )
    }
    
    // JS로 변환된 JSX
    function App() {
    	return React.createElement("div", null, "Hello ", React.createElement("b", null, "react"));
    }

     

    JSX 문법 규칙

    • React DOM은 JSX에 삽입 된 값은 렌더링 완료전 통과하고 JS 작성 시 주입되므로 XSS을 방지하고, 렌더링 후 문자열로 변경되어 값이 표출된다.
    • 브라우저에서 컴파일 시 Babel은 JSX를 React.createElement()로 사용한다.
    • 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다. 즉 여러 요소를 사용 시 반드시 부모요소가 필요하다.
    • <></> 닫힘 태그가 필요하다.
    • JSX 안에 Javascript 표현식 사용시 {}로 감싸야한다.
    • 대소문자를 구분한다.
    • css를 객체형태, 카멜 형식으로 작성해야 한다.
    // html
    <div style="backgroun-color: red; display: block;">hello</div>
    // jsx
    <div style={{ backgrounColor: 'red', display: 'block'}}>hello</div>
    • HTML 어트리뷰트를 정의할때 HTML 속성 값 대신 React DOM의 camelCase 프로터미 명명규칙을 사용 한다. , 역할은 같다. (class className가 되고 tabindex는 tabIndex)
    // html
    <div class="red">hello</div>
    <label for="name" /><input type="text" id="name" />
    // jsx
    <div className={"red"}>hello</div>
    <label htmlFor={"name"} /><input type={"text"} id={"name"} />
    • 주석
    // html
    <div class="red">hello</div> <!-- class 속성 사용 -->
    <!-- 
    <label for="name" /><input type="text" id="name" /> 
    -->
    // js
    rootElement.appendChild(helloElement); // 기본
    /* 
    rootElement.appendChild(helloElement); 
    */ 
    // jsx
    <div className={"red"}>hello</div> // className 속성 사용
    {/*
    <label htmlFor={"name"} /><input type={"text"} id={"name"} />
    *}\

     

    DOM, Virtual DOM

    DOM

    웹페이지를 이루는 태그들을 자바스크립트가 이용할 수 있게끔 브라우저가 트리구조로 만든 객체 모델

     

    프로세스

    • 먼저 브라우저는 HTML 파일을 스크린에 보여주기 위해 DOM 노드 트리 생성, 렌더트리 생성, 레이아웃, 페인팅 과정을 거칩니다. DOM 노드는 HTML의 각 엘리먼트와 연관되어 있기 때문에 HTML 파일에 20개의 변화가 생기면 DOM 노드가 변경되고 그 이후의 과정역시 20회 다시 이루어 집니다.
    • 작은 변화에도 매우 복잡한 과정들이 다시 실행되기 때문에 DOM 변화가 잦을 경우 성능이 저하됩니다.

    Virtual DOM

    • Virtual DOM은 React에서 사용하는 가상 DOM입니다.
    • 상태변화가 일어나면 브라우저 작동 원리에 의해 렌더링 과정이 일어나는데 이때 렌더 트리를 재생성하거나 리플로우, 리페인트 과정이 필요한데, 이러한 과정이 발생되는 많은 연산에서발생하는 비효율성을 최소화하기 위해 탄생한 개념이다.
    • 변경 사항이 발생하면 Virtual DOM에서 먼저 업데이트를 수행한 후 실제 DOM에 반영하여 변화를 최소화하고 성능을 향상시키기 위해 사용됩니다.
    1. 프로세스
      • Virtual DOM은 뷰에 변화가 있다면, 그 변화가 실제 DOM에 적용되기 전에 Virtual DOM에 적용시키고 최종 결과만 실제 DOM에 전달합니다. 따라서 20개의 변화가 있다면 Virtual DOM은 변화된 부분만 가려내어 실제 DOM에 전달하고 실제 DOM은 그 변화를 1회로 인식하여 단 한번의 렌더링 과정만 거치게 됩니다.
        • Diff : 1회로 인식하여 단 한번의 렌더링 과정 / 바뀐부분만 재조정하는 행위

     

    React 기본 문법

    1. 컴포넌트 생성 및 중첩하기

    React는 컴포넌트로 구성된다.
    - component(컴포넌트): 고유한 로직과 모양을 가진 UI

    • React component
    • 정의 : 마크업을 반환하는 자바스크립트 함수이다.
    • 특징 : React 컴포넌트의 이름은 항상 대문자로 시작, HTML 태그는 소문자로 시작
      - MyButton : React component
      - button, div, h1 : HTML 태그 (JSX)
    function MyButton() {
      return (
        <button>
          I'm a button
        </button>
      );
    }
    
    export default function MyApp() {
      return (
        <div>
          <h1>Welcome to my app</h1>
          <MyButton />
        </div>
      );
    }

     

     

    2. JSX로 마크업 작성하기 

    React에서  HTML(마크업 문법)을 JSX라고 한다.
    React 프로젝트는 편의성을 위해 JSX를 사용합니다. 로컬 개발에 권장하는 모든 도구는 JSX를 기본적으로 지원한다.

    • JSX
    • 정의 : React에서  HTML(마크업 문법)
    • 특징 :
      • JSX는 HTML보다 엄격하다.
      • 무조건 태그를 닫아야 한다.
      • 컴포넌트 반환 시 여러 개의 JSX 태그를 사용할 수 없고, 부모로 감싸야 한다. ( <div>...</div> 또는 빈 <>...</>)
    function AboutPage() {
      return (
        <div>
          <h1>About</h1>
          <p>Hello there.<br />How do you do?</p>
        </div>
      );
    }

     

    Fragment 사용하여 JSX 그룹화 하기

    • Fragment는 DOM트리에 추가되지 않는다.
    • <></>로 사용이 가능하다.
    function AboutPage() {
      return (
        <Fragment>
          <h1>About</h1>
          <p>Hello there.<br />How do you do?</p>
        </Fragment>
      );
    }
    function AboutPage() {
      return (
        <>
          <h1>About</h1>
          <p>Hello there.<br />How do you do?</p>
        </>
      );
    }

     

    3. 스타일 추가하기 

    React에서는 className으로 CSS class를 지정한다.
    css 내용은 HTML의 class 어트리뷰트와 동일한 방식으로 동작한다.

    CSS 파일을 임포트하거나, styled-components와 같은 CSS-in-JS 라이브러리를 사용할 수 있습니다. 또한, 인라인 스타일링도 가능합니다.

    /* In your CSS */
    .avatar {
      border-radius: 50%;
    }
    <img className="avatar" />

     

     

    4. 데이터 표시하기 

    JSX를 사용하면 자바스크립트에 마크업이 가능하다.
    중괄호를 사용하면 코드에서 일부 변수를 삽입하여 사용자에게 표시한다.
    - 이스케이프 백 : JSX 어트리뷰트에서 따옴표 대신 중괄호를 사용하여 지정하는 것

    const user = {
      name: 'Hedy Lamarr',
      imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
      imageSize: 90,
    };
    
    return (
    	<>
        	<h1>{user.name}</h1>
            <img
                className="avatar"
                src={user.imageUrl}
                alt={'Photo of ' + user.name}
                style={{
                  width: user.imageSize,
                  height: user.imageSize
                }}
              />
        </>
    );

     

     

    5. 렌더링

    • Render
    • 정의 : 화면에 컴포넌트를 반환하는 행위
    • 특징 : React 안에서는 자바스크립트와 동일한 문법으로 작성 가능하며 JSX 를 포함하여 작성할 수도 있다.

    조건부 렌더링

    조건부 렌더링은 JavaScript의 조건문을 사용하여 컴포넌트의 렌더링을 제어하는 방식입니다. 삼항 연산자나 && 연산자를 사용하여 특정 조건에 따라 다른 컴포넌트를 렌더링할 수 있습니다.

    let content;
    if (isLoggedIn) {
      content = <AdminPanel />;
    } else {
      content = <LoginForm />;
    }
    return (
      <div>
        {content}
      </div>
    );
    <div>
      {isLoggedIn ? (
        <AdminPanel />
      ) : (
        <LoginForm />
      )}
    </div>
    <div>
      {isLoggedIn && <AdminPanel />}
    </div>

     

     

    리스트 렌더링

    리스트를 렌더링할 때는 각 항목에 대해, 형제 항목 사이에서 해당 항목을 고유하게 식별하는 고유한 key 속성을 부여해야 합니다. key는 React가 각 항목을 식별하고 업데이트할 때 성능을 최적화하는 데 도움을 줍니다.

    const products = [
      { title: 'Cabbage', id: 1 },
      { title: 'Garlic', id: 2 },
      { title: 'Apple', id: 3 },
    ];
    
    const listItems = products.map(product =>
      <li key={product.id}>
        {product.title}
      </li>
    );
    
    return (
      <ul>{listItems}</ul>
    );

     

    6. form 

    • 폼을 처리할 때는 각 폼 요소에 상태를 연결하고, onChange 이벤트 핸들러를 통해 상태를 업데이트합니다. 
    • 폼 제출 시 onSubmit 이벤트 핸들러를 사용하여 폼 데이터를 처리

     

    7. 이벤트에 응답하기 

    • event
    • 정의 : 컴포넌트 내부에 이벤트 핸들러 함수를 선언하는 것
    • 특징 : 이벤트 핸들러 함수를 호출하지 않고 전달이 가능하다 (()=>{})
    • React에서는 camelCase 구문을 사용하여 이벤트를 처리합니다. 예를 들어, onclick 대신 onClick을 사용합니다. 이벤트 핸들러는 중괄호 안에 함수로 전달됩니다.
    function MyButton() {
      function handleClick() {
        alert('You clicked me!');
      }
    
      return (
        <button onClick={handleClick}>
          Click me
        </button>
      );
    }

     

    8. 상태 업데이트

    • state는 컴포넌트 내부에서 관리하는 데이터입니다.
    • 이전에는 Ajax 또는 document를 직접 수정하는 작업을 하였지만,   React에서는 useState를 사용하여 간편하게 UI를 업데이트 할 수 있다.
    function MyButton() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1);
      }
    
      return (
        <button onClick={handleClick}>
          Clicked {count} times
        </button>
      );
    }

     

    9. 컴포넌트 간 데이터 공유

    props는 부모 컴포넌트가 자식 컴포넌트에 전달하는 데이터입니다.

    컴포넌트의 독집적인 state 변수를 하위 컴포넌트에서 사용하고, 컴포넌트간 공유하고 싶은 경우 props로 넘겨서 사용합니다.

    props는 읽기 전용으로 전달, 응답시 JSX 중괄호를 사용합니다.

    export default function MyApp() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1);
      }
    
      return (
        <div>
          <h1>Counters that update together</h1>
          <MyButton count={count} onClick={handleClick} />
          <MyButton count={count} onClick={handleClick} />
        </div>
      );
    }

     

    function MyButton({ count, onClick }) {
      return (
        <button onClick={onClick}>
          Clicked {count} times
        </button>
      );
    }

     

     

    10. React Hooks

    React Hook은 함수형 컴포넌트에서 상태와 생명주기 메서드를 활용할 수 있게 도와주는 API이다.

    기본 정의는 React에서 use로 시작하는 함수를 말하며 대표적인 Hook으로 useState, useEffect, useContext 등이 있습니

    https://ko.react.dev/reference/react

     

    React 참고서 개요 – React

    The library for web and native user interfaces

    ko.react.dev

     

    useState 

    Hook은 함수형 컴포넌트에서 상태를 관리하는 데 사용됩니다.

    import React, { useState } from 'react';
    
    const Counter = () => {
      const [count, setCount] = useState(0);
    
      const increment = () => setCount(count + 1);
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={increment}>+1</button>
        </div>
      );
    };

     


    useEffect

    컴포넌트가 렌더링된 후에 실행할 작업을 정의


    useContext

    Context API를 사용하여 컴포넌트 트리 전체에 걸쳐 데이터를 전달할 때 사용합니다. 중첩된 컴포넌트들에 props를 통해 데이터를 전달하는 대신, useContext로 컨텍스트 값을 직접 가져올 수 있습니다.

     

    728x90