-
240112_React카테고리 없음 2024. 1. 12. 17:57
Chapter_01 리액트란?
리액트는 사용자 인터페이슬를 만들기 위한 자바스크립트 라이브러리이며, SPA를 쉽고 빠르게 만들 수 있도록 해주는 도구이다. SPA란, Single Page Applicatiom 의 약자로 하나의 페이지만 존재하는 웹사이트를 의미하며 하나의 HTML 틀을 만들어 놓고 사용자가 특정 페이지를 요청할 때 그 안에 해당하는 페이지의 내용을 채워서 보내주는 것이 SPA이다.
프레임워크과 라이브러리는 비슷한 것 같지만 다르다. 프레임 워크는 내부적인 동작이 정해져 있어 자유도가 낮지만 난이도 또한 낮고 라이브러리는 순수한 함수만 제공한다는 점에서 자유도가 높지만 그만큼 난이도가 높다는 점에서 차이점이 있다.
리액트의 장점과 단점은 아래와 같다.
장점 단점 - 빠른 업데이트와 렌더링 속도 (가상의 DOM)
- 재사용성이 높은 컴포넌트 기반 구조(객체지향적)
- 메타의 든든한 지원
- 활발한 지식 공유와 커뮤니티
- 리액트 네이티브를 통한 모바일 앱 개발 가능- 방대한 학습량
- 높은 상태 관리 복잡도리액트는 내부적으로 Virtual DOM(가상의 DOM)을 사용하며, 웹 페이지와 실제 DOM 사이에서 중간 매개체 역할을 한다. 일반적으로 사용자와 상호작용 하는 웹페이지는 화면의 업데이트가 수시로 이루어지며, 이는 곧 DOm이 수정된다는 말과 동일하다. 이 때 리액트는 DOM의 데이터에서 모두 찾지 않고 업데이트 해야 할 최소한의 부분만 찾아서 업데이트 한다.
또한 리액트는 재사용성이 높은 컴포넌트 기반의 구조를 가지고 있다. 컴포넌트는 구성요소라는 뜻을 가지며, 리액트에서는 모든 페이지가 컴포넌트로 구성되어 있고 하나의 컴포넌트는 여러개의 커포넌트 조합으로 구성될 수 있다는 점에서 재사용성이 높다. 컴포넌트 기반의 구조로 되어있다는 것은 즉, 하나의 컴포넌트가 계속해서 재사용 될 수 있다는 것을 의미한다.
리액트는 메타가 만든 오픈소스로서 꾸준한 지원을 받고 있으며, 커뮤니티가 활성화 되어 있다. 그리고 리액트 네이티브라는 모바일 환경 UI 프레임워크를 사용해 모바일 앱을 개발하는것도 가능하다. 보통 모바일 앱을 개발하기 위해서는 다양한 언어를 배워야 하지만, 리액트 네이티브를 사용하면 자바스크립트 코딩을 통해 안드로이드와 iOS앱을 동시에 출시가 가능하다.
다만, 리액트는 그만큼 학습량이 방대하다는 단점이 있다. 새로운 버전이 업데이트 되면 이에 대한 내용을 숙지하고 있어야 하며, state라는 개념과 관련해서 상태 관리도가 높다는게 리액트의 단점이라고 할 수 있다. state는 리액트 컴포넌트의 상태를 의미하며, 성능 최적화를 위해 state를 잘 관리하는 것이 중요한데 웹사이트의 규모가 커지면 커질수록 컴포넌트의 개수가 많아지면서 상태 관리의 복잡도가 증가한다.
Chapter_02 리액트 시작하기
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>정승연의 블로그</title> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>저의 블로그입니다!</h1> <div id="root"></div> <!-- 리액트 가져오기 --> <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script> <!-- 리액트 컴포넌트 가져오기 --> <script src="MyButton.js"></script> </body> </html>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.js" crossorigin></script>
교재는 React 버전 17을 사용했지만 지금 기준으로 React 버전 18이 나왔기 때문에 위와 같이 수정해서 작성했다.
h1 { color: green; font-style: italic; }
function MyButton(props) { const [isClicked, setIsClicked] = React.useState(false); return React.createElement( "button", { onClick: () => setIsClicked(true) }, isClicked ? "Clicked!" : "Click here!" ); } const domContainer = document.querySelector("#root"); ReactDOM.render(React.createElement(MyButton), domContainer);
리액트 웹 사이트 개발을 위해 create-react-app (CRA) 를 사용했다. 터미널에 아래와 같이 작성해서 패키지를 설치하면 된다 (my-app 은 프로젝트 이름). 아래의 명령어를 하나씩 실행하면 마지막에 리액트 애플리케이션이 로컬 개발 환경에서 실행되고, 열린 주소에서 리액트 로고가 나오는것을 확인할 수 있다.
npm create-react-app my-app cd my-app npm start
하지만 정말 귀찮다.. 답은 인텔리제이다!(듣고있나 JetBrain) 이는 본인의 의견이 아님(feat. 김성래)을 밝힘...
Chapter_03 JSX 소개
JSX는 JavaScript and XML의 앞글자를 딴 것으로, 자바 스크립트의 확장 문법이다. 즉 자바스크립트와 XML/HTML을 함께 사용할 수 있는 문법이며, 아래 코드를 예시로 들었을 때 대입연산자 = 의 오른쪽에 있는 HTML 의 <h1> 태그를 사용해서 hello, world!라는 문자열을 값으로 가지고 온다. 결과적으로 자바스크립트 코드와 HTML이 결합되어, <h1> 태그로 둘러싸인 문자열을 element라는 변수에 저장하는 것이다.
const element = <h1>hello, world!</h1>
JSX는 내부적으로 XML/HTML코드를 자바스크립트로 변환하는 과정을 거쳐 JSX로 코드를 작성해 자바스크립트 코드를 나오게 한다. 여기서 JSX 코드를 자바스크립트로 변환하는 역할을 하는 것이createElement()함수이다. createElement()함수의 파라미터에는 아래와 같은 것이 들어간다.
type은 엘리먼트의 유형을 나타내며, 두번째 파라미터로 props 속성이 들어간다. 마지막 파라미터로 children이 들어가며, 현재 엘리먼트가 포함하고 있는 자식 엘리먼트를 의미한다.
React.createElement( type, //엘리먼트의 유형 [props], //속성 [...children] //현재 엘리먼트가 포함하고 있는 자식 엘리먼트를 의미 )
아래 코드 중 첫 번째 코드는 Hello 라는 이름을 가진 리액트 컴포넌트가 나오고 컴포넌트 내부에서 자바스크립트 코드와 HTML 코드가 결합된 JSX를 사용하고 있는 반면, 두 번째 코드는 JSX를 사용하지 않고 순수 자바스크립트 코드만을 사용해서 동일한 역할을 하도록 만든 코드이다. 두 코드를 비교했을 때 Hello 컴포넌트 내부에서 JSX를 사용했던 부분이 React.createElement() 라는 함수로 대체된 것을 확인할 수 있다.
class Jello extends React.Component { render(){ return <div>Hello {this.props.toWhat}</div>; } } ReactDOM.render( <Hello toWhat="World"/>. document.getElementById('root') );
class Hello extends React.Component{ render(){ return React.createElement('div', null, `Hello ${this.props.toWhat}`); } } ReactDOM.render( React.createElement(Hello, { toWhat: 'world' }, null), document.getElementByID('root') );
JSX의 장점은 크게 세가지로, 코드가 간결해지고, 가독성이 향상되고, Injection Attack을 방어함으로써 보안성이 올라간다는 점이다.
위 코드에서 보았듯, JSX를 사용하지 않았을 경우 리액트의 React.createElement() 함수를 사용해 동일한 코드의 작업을 수행하게 된다. JSX를 사용함으로써 코드가 간결해지므로 가독성이 향상되고 의미가 훨신 더 빠르게 와닿게 된다. 이는 코드의 길이가 짧아지는것에서 나아가 유지보수 관점에서도 중요한 의미를 가진다. 또한 Injection Attack이라 불리는 해킹방법을 방어함으로서 보안성이 올라가게 된다 (Injection Attack는 입력창에 소스코드를 입력해 해당 코드가 실행되도록 만드는 해킹 방법이다).
JSX는 자바스크립트 문법을 지원하므로 자바스크립트 문법에 XML과 HTML을 섞어서 사용하면 된다.
아래와 같이 엘리먼트를 선언하는 부분의 코드처럼 HTML과 자바스크립트가 섞인 형태로 코드를 작성하며, XML/HTML코드 중간에 자바스크립트 코드를 사용하려면 중괄호를 써서 묶어준다 (아래 코드 중 {name}으로 표시된 부분).
const name = '소플'; const element = <h1>안녕,{name}</h1> ReactDom.render( element, document.getElementById('root') );
아래 코드에서는 HTML코드 사이에 괄호를 사용해 변수가 아닌 formatName()이라는 자바 스크립트 함수를 호출해 사용한다.
function formatName(user){ return user.firstName+' '+user.lastName; } const user = { firstName: 'Inje', lastName: 'Lee' }; const element = ( <h1> Hello, {formatName(user)} </h1> ); ReactDom.render( element, document.getElementById('root') );
아래 코드에서는 사용자가 존재하면 formatName()이라는 함수를 써서 포매팅 된 이름을 출력하고, 그렇지 않을 경우 Stranger에게 하는 인사말을 출력한다.
function getGreetion(user){ if(user){ return <h1>hello, {formatName(user)}!</h1>; } return <h1>Hello, Stranger.</h1> }
html 태그 속성에 값을 넣고 싶다면 아래와 같이, 큰 따옴표 사이에 문자열을 넣거나 중괄호 사이에 자바스크립트 코드를 넣는다. JSX에서는 중괄호를 사용하면 무조건 자바스크립트 코드가 들어간다.
큰 따옴표 사이에 문자열을 넣거나 const element = <div tabIndex="0"></div> 중괄호 사이에 자바스크립트 코드를 넣으면 된다 const element = <img src={user.avatarUrl}></img>;
JSX을 사용해 children을 정의하려면 아래와 같이, HTML을 사용하듯 상위 태그가 하위태그를 둘러싸도록 한다. 여기에서 <div>태그의 children은 <h1>태그와 <h2>태그가 된다.
const element = ( <div> <h1>안녕하세요</h1> <h2>리액트를 공부해요<h2> </div> );
Chapter_03.5 JSX 코드 작성
vsCode로 create-react-app을 이용해 만든 프로젝트를 열고 chapter_03폴더를 생성한 뒤 Book.jsx , Library.jsx를 생성해 아래와 같이 작성한다. 이후 생성한 컴포넌트를 화면에 렌더링 하기 위해 index.js파일을 아래와 같이 수정한다. 모든 코드 작성이 끝나면 리액트 애플리케이션을 실행한다. vsCode의 터미널을 실행시킨 뒤, npm start 명령어를 실행하면 웹 브라우저에 새 창이 열리면서 컴포넌트들이 렌더링 된 것을 확인 할 수 있다.
Book.jsx import React from "react"; function Book(props){ return( <div> <h1>{`이 책의 이름은 ${props.name} 입니다.`}</h1> <h2>{`이 책은 총 ${props.numOfPage}페이지로 이뤄져 있습니다.}`}</h2> </div> ) } export default Book;
Library.jsx import React from "react"; import Book from "./Book"; function Library(props){ return ( <div> <Book name="처음 만난 파이썬" numOfPage={300}></Book> <Book name="처음 만난 AWS" numOfPage={400}></Book> <Book name="처음 만난 리액트" numOfPage={500}></Book> </div> ); } export default Library;
index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import reportWebVitals from './reportWebVitals'; import Library from './chapter_03/Library'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Library /> </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
Chapter_04 엘리먼트 렌더링
리액트 Element란 리액트 앱을 구성하는 요소를 의미한다. 즉, 리액트 엘리먼트는 화면에 보이는 것을 기술하며, 엘리먼트가 기술한 내용을 토대로 실제 화면에서 보게 되는 DOM 엘리먼트가 만들어진다. 결국 리액트 엘리먼트는 DOM 엘리먼트의 가상 표현이라고 할 수 있다.
엘리먼트의 생김새는 자바스크립트 객체 형태로 존재하며, 생성 후에는 불변성을 가지고 있어 자식이나 속성을 바꿀 수 없다. 따라서 화면에 변경된 엘리먼트를 보여주기 위해서는 엘리먼트를 변경하는것이 아닌, 새로운 엘리먼트를 만들어 기존 엘리먼트와 바꿔야 한다.
엘리먼트를 생성한 뒤 화면에 출력하기 위해서는 렌더링을 해야 하는데, 렌더링은 ReactDOM 의 render()라는 함수를 이용해서 할 수 있다.
이 함수는 첫 번째 파라미터인 리액트 엘리먼트를 두 번쨰 파라미터 HTML 엘리먼트에 렌더링 하는 역할을 한다. 여기서 리액트 엘리먼트는 리액트의 Virtual DOM 가상 돔에 존재하는 것이고, HTML 엘리먼트는 실제 브라우저의 DOM에 존재하는 것이다. 결국 리액트의 엘리먼트가 렌더링 되는 과정은 Virtual DOM 가상 돔에서 실제 DOm으로 이동하는 과정인 것이다.
렌더링 된 엘리먼트는 불변성을 가진다. 즉, 한번 생성되면 바꿀 수 없기 때문에 엘리먼트를 업데이트 하기 위해서는 다시 생성해야 한다. 하지만 아래 코드에서는 tick()이라는 함수를 정의하고 있고, tick() 함수는 현재 시간을 포함하고 있는 엘리먼트를 생성해 root div에 렌더링 하는 역할을 한다. 그리고 자바스크립트의 setInterval()함수를 사용해 tick()함수를 매 초 호출하고 있다. 이 코드를 렌더링 하면, 뷰에서는 매 초 화면에 새로운 시간이 나오는 것 처럼 보이겠지만 내부적으로는 tick()함수가 호출 될 때마다 새로운 엘리먼트를 생성해 바꿔치기를 하는 것이다.
export default Clock; function tick(){ const element = ( <div> <h1>안녕, 리액트!</h1> <h2>현재 시간: {new Date().toLocaleTimeString()}</h2> </div> ); ReactDOM.render(element, document.getElementById('root')); } setInterval(tick, 1000)
Chapter_04.4 시계 만들기
Chapter04.4를 진행하다보니 리액트의 버전이 맞지 않아 에러가 떴다. 교재는 17버전을 사용하고 있으므로 교재와 동일하게 코드를 작성하려면 React17버전을 쓰면 되겠지만 새로운 버전에 맞게 작성해보고 코드를 이해하는 편이 도움이 될 거라고 생각해서 18버전으로 계속 쓰기로 함. 리액트 18버전을 사용하므로 그에 맞춰서 코드를 수정해서 작성했다.
코드 에러가 뜨는 부분들은 구글링+GPT의 도움을 좀 받았다.
react render is not a function
Uncaught TypeError: react_dom_client__WEBPACK_IMPORTED_MODULE_1__.render is not a function
문제점 React로 간단한 시계(Clock) 컴포넌트를 만들고 index.js 파일을 수정하고 렌더링 했지만, 화면에 아무것도 나타나지 않음 콘솔을 보니 > Uncaught TypeError: reactdomclientWEBPACKIMPORTEDMODULE_1.render is not
velog.io
한빛출판네트워크
더 넓은 세상, 더 나은 미래를 위한 아시아 출판 네트워크 :: 한빛미디어, 한빛아카데미, 한빛비즈, 한빛라이프, 한빛에듀
hanbit.co.kr
import React from "react"; function Clock(props) { return( <div> <h1>안녕, 리액트!</h1> <h2>현재 시간: {new Date().toLocaleTimeString()}</h2> </div> ); } export default Clock;
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import reportWebVitals from './reportWebVitals'; import Clock from './chapter_04/Clock'; const root = ReactDOM.createRoot(document.getElementById('root')); setInterval(() => { root.render( <React.StrictMode> <Clock /> </React.StrictMode> ); }, 1000); reportWebVitals();
위 코드에서 임포트를 아래처럼 수정하면 리액트 17버전의 코드로 작성해도 에러가 뜨지 않는다고 하는데 나는 작성해보지 않았다.
import ReactDOM from 'react-dom';