2023.06.28 react 맛보기

이무헌·2023년 7월 21일
0

react

목록 보기
13/19
post-thumbnail

1.리액트란?

💡 react 첫날 react는 메타에서 2011년쯤에 만들었다. react는 개발자들 사이에서 라이브러리다 프레임워크다 얘기가 많은데 공식 문서에서도 라이브러리다 라고 얘기를 하는데

라이브러리,프레임워크의 차이
라이브러리: 폴더의 구조가 없음.
프레임 워크:폴더 구조가 있음.

패키지를 설치 할 수 있기 때문에
리액트 개발을 할 때 편하게 초기 세팅을 설치받아서 사용할 수 있다.
메타에서 개발한 것은 react와 react-router 라이브러리
메타에서 개발하고 오픈소스에 기여중임~

리액트를 프레임워크라고 하는 이유?
메타에서 라이브러리를 개발하고
npx create-react-app [폴더명] 구문으로 패키지를 제공해서
react를 개발할 때 권장 개발환경을 구성해준다.
react 프로젝트 설정
그래서 블로그나 개발자들 사이에서 프레임워크라고 하는것.

리액트는 화면을 구성할 때 자바스크립트를 활용해서 html을 조작해줌 dom
효율적인 브라우저 랜더링을 위해
페이지를 효율적으로 업데이트 하기 위해서
react는 가상 DOM을 사용해서 변경된 부분만 다시그림.(업데이트)
일반적인 html은 변경된 부분만 업데이트 하지않고 전체 페이지를 다시 그려주는데
react의 가상 DOM은 메모리에 남아있고 실제 페이지의 DOM은 분리되어있는 상태
react의 상태가 변하면 새 가상 DOM이 생성되고 이전 상태의 가상 DOM과 비교해서
업데이트 해야할 부분믕 찾고 (틀린그림 찾기) 실제 DOM에 업데이트를 해준다.
그래서 효율적인 업데이트가 가능하다.

react를 사용하는 이유
react의 부분 랜더링
react는 view 중심 보여주는 것에 집중된 라이브러리

PHP EJS 이런 SSR
서버에서 페이지를 완성 시켜서 브라우저에 응답해주는것.

클라이언트에서 페이지를 구성하는 것을 하고싶다.
랜더링을 클라이언트 측에서 하고 싶었던것
CSR => React, vue, angular

react는 DOM의 조작을 쉽게 하기 위해서 사용을 하고
SPA를 만들기 위해서 사용한다.
하나의 페이지에서 내용을 바꿔서 페이지가 전환된것 처럼 보여준다.

react를 만든 사람은 자바스크립트를 잘하는 사람들이 만든건 아니고 그냥 개발을 잘하는 사람들이 만든것
class문법으로 되어있음.

다음은 chatGPT의 대답이다.

🖥️

React(또한 React.js 또는 ReactJS로 알려져 있음)는 사용자 인터페이스를 구축하기 위한 인기있는 JavaScript 라이브러리로, 특히 싱글 페이지 애플리케이션에 사용됩니다. 이것은 Facebook에서 개발되고 유지되고 있습니다.

React는 페이지 새로고침 없이 데이터 변경에 따라 효율적으로 업데이트하고 렌더링 할 수 있는 대규모 웹 애플리케이션을 만들 수 있게 합니다. React의 핵심 목표는 가능한 최고의 렌더링 성능을 제공하는 것입니다. 그 힘은 전체 웹 페이지가 아닌 개별 컴포넌트에 초점을 맞추는 데서 나옵니다.

다음은 React의 주요 기능입니다:

  1. 컴포넌트 기반: React는 컴포넌트를 중심으로 구축됩니다. 이들은 사용자 인터페이스(UI)의 일부를 렌더링하는데 책임이 있는 독립적인 코드 조각(일반적으로 JS, HTML, CSS)입니다. UI를 컴포넌트로 분해함으로써 코드를 재사용할 수 있고 애플리케이션을 더 쉽게 이해하고 유지 관리할 수 있습니다.
  2. 가상 DOM: React는 성능 향상을 위해 가상 DOM을 사용합니다. 객체의 상태가 변경되면 React는 먼저 가상 DOM에서 연산을 수행한 다음 차이 분석 알고리즘을 사용하여 실제 DOM을 직접 업데이트하는 대신 가상 DOM에서 무엇이 변경되었는지를 식별합니다. 이 과정은 비용이 많이 드는 실제 DOM의 직접 조작을 피하므로 업데이트가 더 빠르고 효율적이게 됩니다.
  3. 단방향 데이터 바인딩: React는 단방향 데이터 흐름을 사용합니다. 이는 React 애플리케이션을 설계할 때 개발자가 자주 부모 컴포넌트 내에 자식 컴포넌트를 중첩한다는 것을 의미합니다. 이러한 단방향 데이터 흐름은 복잡성을 제어하는 데 도움이 되며, 데이터가 어디에서 오는지 및 어떻게 수정되는지 추적하는 것이 더 쉬워집니다.
  4. JSX: 이것은 JavaScript에 대한 구문 확장으로 HTML을 닮았습니다. UI가 어떻게 보여야 하는지 설명하는 데 React와 함께 사용됩니다. JSX는 처음에는 혼란스러울 수 있지만, JavaScript에 강력한 추가로서 React 코드를 더 읽기 쉽고 쉽게 작성할 수 있게 해줍니다.

⇒뒤에 있는 훅과 redux는 아직 배우지 않았으니 언급하지 않겠다.

2.react vanilla JS로 구현해보기

  • state 구현해보기
    • 전체 코드
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Document</title>
        </head>
        <body>
          <div id="root"></div>
        </body>
        <script>
          const root = document.querySelector("#root");
          // DOM을 직접 다루지 않고 state(상태값)으로 랜더링
          let state = {
            items: ["아이템1", "아이템2"],
          };
          const setState = (_state) => {
            // 초기 상태값에 추가로 새로운 상태값
            state = { ...state, ..._state };
            render();
          };
          // 랜더링 해줄 함수
          const render = () => {
            // 상태값이 아닌 변수를 그냥 사용하면
            // 변수를 다시 선언해서 초기화 된다.
            // 그러면 보관해야하는 값은 상태값으로 보관을 해야한다.
            let temp = 0;
            const { items } = state;
            root.innerHTML = `
            <ul>
                ${items.map((a) => {
                  return `<li>${a} </li>`;
                })} 
                </ul>
                <button id='append'> 추가</button>
            `;
            document.querySelector("#append").addEventListener("click", () => {
              //state 변경 시키자.
              // react는 상태값을 주시하고 있는데
              // 상태를 주시하고 있는 이유는 상태가 변하면 리랜더링 시킨다.
              // setState으로만 변경을 하자고 약속함.
              setState({ items: [...items, `아이템 ${items.length + 1}`] });
              console.log(temp);
              temp++;
            });
          };
          // 최초 화면 그려주기
          render();
        </script>
      </html>
    • state 생성
      let state = {
            items: ["아이템1", "아이템2"],
          };
      • 초기 state를 다음과 같이 설정하였다.
      • 이 스테이트 값은 setState함수로 바뀔 것이다.
    • setState함수
      const setState = (_state) => {
            // 초기 상태값에 추가로 새로운 상태값
            state = { ...state, ..._state };
            render();
          };
      • spread operator 를 이용해 기존 state에 _state를 업데이트 해주었다.
      • 그 후 render()를 해준다.
    • render함수
      const render = () => {
            // 상태값이 아닌 변수를 그냥 사용하면
            // 변수를 다시 선언해서 초기화 된다.
            // 그러면 보관해야하는 값은 상태값으로 보관을 해야한다.
            let temp = 0;
            const { items } = state;
            root.innerHTML = `
            <ul>
                ${items.map((a) => {
                  return `<li>${a} </li>`;
                })} 
                </ul>
                <button id='append'> 추가</button>
            `;
            document.querySelector("#append").addEventListener("click", () => {
              //state 변경 시키자.
              // react는 상태값을 주시하고 있는데
              // 상태를 주시하고 있는 이유는 상태가 변하면 리랜더링 시킨다.
              // setState으로만 변경을 하자고 약속함.
              setState({ items: [...items, `아이템 ${items.length + 1}`] });
              console.log(temp);
              temp++;
            });
          };
      • root 태그에 새로운 li를 붙여준다. 이 때 append버튼을 눌렀을 때 setState를 업데이트 해주고 render()를 함으로서 다시 ul을 업데이트 해준다.
  • component 구현해보기
    • 전체 코드
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Document</title>
        </head>
        <body>
          <div id="root"></div>
        </body>
        <script>
          // react의 UI의 기본 단위 컴포넌트
          // 컴포넌트는 자주 사용할 것 같은 UI요소의 기본단위 (재사용성)
      
          // 컴포넌트는 상태와 속성을 가지고 있어요.
          // react 단방향성 데이터의 흐름
          // 부모에서 자식으로 값을 전달해줄 수 있다.
      
          // class
          // 컴포넌트 클래스
          // 컴포넌트의 모양을 만들거고 상속 받아서 사용할 거임
          class Component {
            target;
            state; //상태값 컴포넌트의 유지되는 데이터
      
            constructor(target) {
              // 컴포넌트의 target을 설정
              this.target = target;
              this.setUp();
              this.render();
              console.log("최초 render");
            }
      
            //   초기 설정
            setUp() {
              // 컴포넌트를 초기 설정 랜더링 하기전에 동작하는 함수.
              console.log("initialize");
            }
            template() {
              // 컴포넌트 HTML 템플릿을 반환 해줄거임
              return "없음";
            }
            render() {
              // 컴포넌트를 타겟 요소에 그리기
              this.target.innerHTML = this.template();
              this.setEvent();
            }
            setEvent() {
              // 컴포넌트 이벤트 세팅
              console.log("컴포넌트 이벤트 세팅");
            }
            setState(_state) {
              // 컴포넌트의 상태를 업데이트
              // 업데이트 되면 리렌더링
              this.state = { ...this.state, ..._state };
              console.log(this.state,'asd',_state)
              this.render();
              console.log("state changed");
            }
          }
          // 가상 DOM클래스 정의
          // 렌더링 시킬거임
          class VirtualDOM {
            constructor(component, target) {
              // 매개변수로 전달받은 컴포넌트 생성후 타겟 요소 전달.
              // 컴포넌트 클래스 생성자 함수의 매개 변수로 타겟 전달
              this.Component = new component(target);
            }
            render() {
              this.Component.template();
            }
          }
      
          // App class 컴포넌트 상속 받아서 정의
          class App extends Component {
            setUp() {
              // App 컴포넌트 초기세팅 함수
              this.state = { items: ["아이템1", "아이템2"] };
            }
      
            template() {
              // App 컴포넌트의 HTML을 생성 해서 반환
              const { items } = this.state;
              console.log(items)
              return `
              <ul>
                  ${items.map((a) =>  `<li>${a} </li>`)}
                  </ul>
                  <button> 추가</button>
                  `;
            }
            setEvent() {
              // App 컴포넌트의 이벤트 등록
              this.target.querySelector("button").addEventListener("click", () => {
                const { items } = this.state;
                this.setState({ items: [...items, `아이템 ${items.length + 1}`] });
              });
            }
          }
          // root 선택자로 잡고
          const root = new VirtualDOM(App, document.querySelector("#root"));
          root.render()
        </script>
      </html>
    • 상속 할 Component class
      class Component {
            target;
            state; //상태값 컴포넌트의 유지되는 데이터
      
            constructor(target) {
              // 컴포넌트의 target을 설정
              this.target = target;
              this.setUp();
              this.render();
              console.log("최초 render");
            }
      
            //   초기 설정
            setUp() {
              // 컴포넌트를 초기 설정 랜더링 하기전에 동작하는 함수.
              console.log("initialize");
            }
            template() {
              // 컴포넌트 HTML 템플릿을 반환 해줄거임
              return "없음";
            }
            render() {
              // 컴포넌트를 타겟 요소에 그리기
              this.target.innerHTML = this.template();
              this.setEvent();
            }
            setEvent() {
              // 컴포넌트 이벤트 세팅
              console.log("컴포넌트 이벤트 세팅");
            }
            setState(_state) {
              // 컴포넌트의 상태를 업데이트
              // 업데이트 되면 리렌더링
              this.state = { ...this.state, ..._state };
              console.log(this.state,'asd',_state)
              this.render();
              console.log("state changed");
            }
          }
      • constructor(target) 생성자 함수로 현재 target을 정해준다.
      • setUp()으로 초기 설정을 하고 render()로 페이지를 그려준다.
      • template() 으로 html을 변경시켜준다.
      • setEvent() 로 이벤트를 설정한다.
      • setState(_state) 로 state를 변경하고 render함으로서 다시 페이지를 그려준다.
      • render()로 페이지를 그려주고, template()로 변경시킨 html을 target.innerHTML에 삽입한다. 그 후 setEvent()로 이벤트를 생성시켜준다.
    • Component 를 상속받을 class App
      class App extends Component {
            setUp() {
              // App 컴포넌트 초기세팅 함수
              this.state = { items: ["아이템1", "아이템2"] };
            }
      
            template() {
              // App 컴포넌트의 HTML을 생성 해서 반환
              const { items } = this.state;
              console.log(items)
              return `
              <ul>
                  ${items.map((a) =>  `<li>${a} </li>`)}
                  </ul>
                  <button> 추가</button>
                  `;
            }
            setEvent() {
              // App 컴포넌트의 이벤트 등록
              this.target.querySelector("button").addEventListener("click", () => {
                const { items } = this.state;
                this.setState({ items: [...items, `아이템 ${items.length + 1}`] });
              });
            }
          }
      • setUp() 을 오버라이딩해 state를 변경한다.
      • template()을 오버라이딩하여 html을 return 한다.
      • setEvent() 로 버튼 클릭 이벤트를 부여한다. setState를 실행시켜 state를 변경시키는 이벤트를 실행한다.
  • 가상 VirtualDOM 구현하기(component 연결)
    class VirtualDOM {
          constructor(component, target) {
            // 매개변수로 전달받은 컴포넌트 생성후 타겟 요소 전달.
            // 컴포넌트 클래스 생성자 함수의 매개 변수로 타겟 전달
            this.Component = new component(target);
          }
          render() {
            this.Component.template();
          }
        }
    • 생성자로 받은 component 와 taget을 이어주었다.
    • 그 component의 render()를 실행시켜준다.
  • 실행
    const root = new VirtualDOM(App, document.querySelector("#root"));
        root.render()

3.react 맛보기

  • state react로 구현해보기
    • 전체코드
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Document</title>
        </head>
        <!-- React,ReactDOM라이브러리 -->
        <script
          crossorigin
          src="https://unpkg.com/react@18/umd/react.development.js"
        ></script>
        <script
          crossorigin
          src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
        ></script>
        <!-- React,ReactDOM라이브러리 -->
        <!-- Babel을 가져와서 JSX 문법을 사용 -->
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
        <!-- Babel을 가져와서 JSX 문법을 사용 -->
        <!-- 자바스크립트 ㅋ드를 변환 해주는 착한 도구 babel
          자바 스크립트를 컴파일 해준다.
          자바 스크립트 문법은 꾸준히 진화를 했는데
          자바 스크립트 문법이 진화하면,ES6=>ES5 변환
          babel을 통해서 문법을 쉽게 고칠 수 있다.
          babel은 JSX구문을 브라우저에서 읽을 수 있는 자바스크립트로도 변환 해준다. -->
        <body>
          <div id="root"></div>
        </body>
        <script type="text/babel">
          class LoginBtn extends React.Component {
            constructor(props) {
              // 부모 생성자 함수 호출
              super(props);
              // 컴포넌트의 상태
              this.state = {
                isLogin: false,
              };
            }
            render() {
              return (
                // {} 중괄호는 EJS때 <% %> 자바스크립트 구문을 사용하겠다는 의미
                <button
                  onClick={() => {
                    // 현재 상태의 반대값으로 준것.
                    this.setState({ isLogin: !this.state.isLogin });
                  }}
                >
                  {this.state.isLogin ? "Logout" : "Login"}
                </button>
              );
            }
          }
          // 루트 요소를 가상 DOM으로 생성
          // createRoot 메서드 랜더링을 위한 루트 객체를 생성
          // 루트를 root 아이디를 가진 태그로 설정
          const root = ReactDOM.createRoot(document.querySelector("#root"));
          // JSX문으로 LoginBtn 컴포넌트를 root에 렌더링한다.
          root.render(<LoginBtn id='2'>버튼이다</LoginBtn>);
        </script>
      </html>
    • React.Component 로 클래스 구현
      class LoginBtn extends React.Component {
            constructor(props) {
              // 부모 생성자 함수 호출
              super(props);
              // 컴포넌트의 상태
              this.state = {
                isLogin: false,
              };
            }
            render() {
              return (
                // {} 중괄호는 EJS때 <% %> 자바스크립트 구문을 사용하겠다는 의미
                <button
                  onClick={() => {
                    // 현재 상태의 반대값으로 준것.
                    this.setState({ isLogin: !this.state.isLogin });
                  }}
                >
                  {this.state.isLogin ? "Logout" : "Login"}
                </button>
              );
            }
          }
      • 생성자 함수로 생성한 후 state를 바로 지정한다.
      • 이 때 state변수는 생성하지 않아도 된다.
      • render()함수를 실행시키면 return에 있는 jsx가 반환된다.
    • root지정 후 component붙여주기
      const root = ReactDOM.createRoot(document.querySelector("#root"));
          // JSX문으로 LoginBtn 컴포넌트를 root에 렌더링한다.
          root.render(<LoginBtn id='2'>버튼이다</LoginBtn>);
      • root를 root로 지정한 후 render를 통해 버튼이다 로 html을 그려준다. Componenet는 이와같이 넣어주면 된다.
  • component react로 구현해보기
    • 전체코드
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Document</title>
        </head>
        <script
          crossorigin
          src="https://unpkg.com/react@18/umd/react.development.js"
        ></script>
        <script
          crossorigin
          src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
        ></script>
        <!-- React,ReactDOM라이브러리 -->
        <!-- Babel을 가져와서 JSX 문법을 사용 -->
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
        <body>
          <div id="root"></div>
        </body>
        <script type="text/babel">
      
          class Clock extends React.Component {
            constructor(props) {
              super(props);
              this.state = {
                time: new Date().toLocaleTimeString(),
              };
            }
      
            // react 생명주기
            // react생명주기란 화면이 그려지는 시기와 state값이 변했을 때 동작해야하는 작업이 있을 경우
            // 화면이 그려지는 시기와 state값이 변했을 때 동작해야하는 작업이 있을경우
            // 이런 부분을 제어 할 수있게 해주는 것이 lifecycle 함수이다.
            update() {
              setState({});
              // 아직 변경전 상태가 찍힘
              // console.log(this.state);
            }
            componentDidMount() {
              // 여기 내용이 컴포넌트가 생성되면 호출됨 딱 최초에 한 번
              setInterval(() => {
                this.setState({ time: new Date().toLocaleTimeString() });
              }, 1000);
              console.log("최초 한 번 실행됨");
              // 최초 한 번 실행됨
            }
            componentDidUpdate() {
              console.log("state updated!");
            }
            render() {
              return (
                <>
                  <h1>안뇽, 내 컴퓨터 시간</h1>
                  <h2>time:{this.state.time}</h2>
                </>
              );
            }
          }
          const root = ReactDOM.createRoot(document.querySelector("#root"));
          root.render(<Clock></Clock>);
        </script>
      </html>
    • component 구현해보기(Clock)
      class Clock extends React.Component {
            constructor(props) {
              super(props);
              this.state = {
                time: new Date().toLocaleTimeString(),
              };
            }
      
            // react 생명주기
            // react생명주기란 화면이 그려지는 시기와 state값이 변했을 때 동작해야하는 작업이 있을 경우
            // 화면이 그려지는 시기와 state값이 변했을 때 동작해야하는 작업이 있을경우
            // 이런 부분을 제어 할 수있게 해주는 것이 lifecycle 함수이다.
            update() {
              setState({});
              // 아직 변경전 상태가 찍힘
              // console.log(this.state);
            }
            componentDidMount() {
              // 여기 내용이 컴포넌트가 생성되면 호출됨 딱 최초에 한 번
              setInterval(() => {
                this.setState({ time: new Date().toLocaleTimeString() });
              }, 1000);
              console.log("최초 한 번 실행됨");
              // 최초 한 번 실행됨
            }
            componentDidUpdate() {
              console.log("state updated!");
            }
            render() {
              return (
                <>
                  <h1>안뇽, 내 컴퓨터 시간</h1>
                  <h2>time:{this.state.time}</h2>
                </>
              );
            }
          }
      • 리액트의 라이프 사이클 중 componentDidMount 🖥️ *componentDidMount()**는 컴포넌트가 마운트(즉, 트리에 삽입)된 직후에 호출됩니다. DOM 노드가 필요한 초기화는 여기로 이동해야 합니다. 이 방법은 네트워크 요청과 같은 구독을 설정하기에 좋은 곳입니다. 그러나 메모리 누수를 유발할 수 있으므로 componentWillUnmount()에서 구독을 취소하는 것을 잊지 마십시오. 출처:chatGPT ```jsx componentDidMount() { // 여기 내용이 컴포넌트가 생성되면 호출됨 딱 최초에 한 번 setInterval(() => { this.setState({ time: new Date().toLocaleTimeString() }); }, 1000); console.log("최초 한 번 실행됨"); // 최초 한 번 실행됨 } ``` - 처음 렌더링 됐을 때 정의된 함수가 한 번 실행된다. - 1초에 한 번씩 state를 변경한다. 이 때 rendering이 진행되며 html이 바뀌게 된다.
      • 리액트의 라이프 사이클 중 componentDidUpdate 🖥️ componentDidUpdate(prevProps, prevState, snapshot)는 업데이트가 발생한 직후 호출됩니다. 이 메서드는 초기 렌더링에 대해 호출되지 않습니다. 이것은 DOM으로 작업하거나 소품의 변경 사항에 따라 새 데이터를 가져오기에 좋은 곳입니다. ```jsx componentDidUpdate() { console.log("state updated!"); } ``` - state가 업데이트 될 때마다 실행된다.
      • root를 정하고 render하기
        const root = ReactDOM.createRoot(document.querySelector("#root"));
            root.render(<Clock></Clock>);

4.느낀점

🖥️ 리액트를 다시 접하면서 낮선 코드가 많이 보인다. 특히 class와 render()함수는 함수형 코딩을 했던 나에게 아직 익숙하지가 않다. 다재다능한 개발자가 되기 위해 필요한 기술들을 차근차근 배우고 언젠가 써먹을 곳이 있다는 생각으로 공부해야겠다.
profile
개발당시에 직면한 이슈를 정리하는 곳

0개의 댓글

관련 채용 정보