Why React?
모든 기술은 현재 세상의 불편한 점을 해결하기 위해서 만들어졌고, 발전해왔다. 그래서 기술을 배운다는 것은 단순히 사용법만 배우는 것을 의미하지 않는다. 그렇게 단순 사용법만 배우게 되면 기술에 대한 시야가 좁아지게 된다. 기술에 대한 시야가 좁아지게 된다는 건 문제 해결 능력이 부족하다고도 생각해 볼 수도 있다. 단순히 사용법만 배워서 시야가 좁아진 사람은 내가 배운 대로가 아니면, 또는 내가 겪어본 일이 아니면 해결할 수가 없게 되고, 심하면 해결할 의지도 갖지 못하게 된다. 이런 개발자를 원하는 회사는 없다. 따라서 우리는 리액트라는 기술이 세상에 왜 필요했고, 왜 훌륭한 기술로 평가 받고 있으며, 결론적으로 많은 사람들에게 어떻게 이렇게 많은 사랑을 받을 수 있었는지 알아보는 시간을 갖도록 하겠다.
html로 작성했을 때 중복되는 코드가 너무 많다는 것이 문제점이다.
Shotgun Surgery (산탄총 수술)
기존 방식 → 컴포넌트화 방식
React는 Component 기반의 UI 라이브러리
명령형 프로그래밍 vs 선언형 프로그래밍
명령형 프로그래밍
: 절차를 하나하나 다 나열해야 함
선언형 프로그램
: 그냥 목적을 바로 말함
Create React App
npx : 새로운 도구는 아니고 npm을 조금 더 편리하게 이용하기 위해서 존재하는 도구. 설치되어 있지 않은 패키지를 딱 한 번만 쓰고 싶을 때 사용하는 도구
npx -v 명령어를 입력했을 때 버전이 출력되어야 성공적으로 설치가 되어 있는 것이다.
npx create-react-app reactexam1
create-react-app이라는 패키지 자체도 결국에는 node.js 기반 패키지이기 때문에, 이런 식으로 기본 구성은 다 똑같다는 것이다. React 말고도, Vue.js나 등등.. 뒤에 js가 붙는 프론트엔드 프레임워크는 대다수 이런 구조를 가지고 있다고 생각해주면 된다.
Script : 명령어를 키워드로 지정하도록 하는 것
웹 서버를 종료하고 싶다면?
터미널에서 Ctrl + C
일괄 작업을 끝내시겠습니까 (Y/N)? : Y
Src 폴더 - App.js
html 파일이 없는데 어떻게 자바스크립트 코드만으로 화면이 표시되는 건지 의문이 든다. F12를 통해 html 코드를 확인해보자.
App 함수가 리턴하는 값이 id가 root인 div 아래로 들어간다.
root라는 id를 갖는 div는 어디에 있느냐? public 디렉토리의 index.html에 있다.
리액트 앱이 실행되면서 src 디렉토리 밑에 index.js가 실행이 되면서 index.html에 있는 id가 root인 div 아래로 App.js 안에 있는 App 함수가 리턴하는 값들이 들어간다.
node_modules : node.js 패키지의 구성 요소 중 하나로, 외부 모듈을 저장하고 있는 폴더. 심지어 리액트도 외부 모듈이기 때문에 node_modules 안에 저장되어 있다.
작업한 것을 다른 사람에게 보낼 때 node_modules까지 함께 보내면 시간이 무지막지하게 많이 걸릴 것이다. 하지만 그럴 필요가 없다. node.js 패키지는 node_modules가 없어도 괜찮다. 왜 괜찮냐? node_modules가 지워져서 어떤 모듈을 사용해야 하는지가 package.json과 package-lock.json에 명시가 되어있기 때문이다. 만약 node_modules가 없는 패키지를 다운 받았다면 npm i 명령어를 통해 node_module을 다시 다운로드 받을 수 있다.
favicon.ico : 아이콘 파일 : 홈페이지 아이콘
logo192.png, logo512.png, manifest.json
이 세 개는 모바일에서 홈 화면에 추가하거나 그럴 때 필요한 것. 지금은 잠시 제껴두겠다.
src : source
App.css : Style
JavaScript와 html을 합쳐서 사용할 수 있는 문법을 자바스크립트 표현식, JavaScript Extension, 즉 JSX라고 부른다. JSX 문법은 자바스크립트의 변수나 함수 같은, 그냥 값을 html에 쉽게 포함해서 사용할 수 있도록 고안된 문법이다.
Add.js의 Add 함수를 export해서 index.js에서 사용했다.
그러면 다른 파일에서도 사용할 수 있겠다.
이렇게 별도의 html 요소들을 묶어서 모듈처럼 만들고 내보내서 다른 파일에서 사용할 수 있도록 하는 개념 : 컴포넌트 방식
리액트는 App이라는 함수를 만들고, return으로 JSX 문법의 html을 리턴해주면서 컴포넌트를 만들 수 있다.
export default App;
es module system
App.js에서 export default로 내보낸 함수를 다른 파일에서 import App(이름) from "./App"(경로);
export default는 한 개만 내보낼 수 있다.
React App을 만드는 방법
Create React App : 이미 세팅 완료된 패키지
localhost:3000
: 자신의 컴퓨터를 가리키는 주소
크롬 웹 브라우저가 pc에 요청을 날렸고, pc는 이런 React 앱을 반환했다는 뜻이다.
npm start 명령어를 이용해서 React 앱을 실행시킨 순간, 해당 컴퓨터는 웹 서버가 된 것이다.
그러면 크롬 브라우저는 해당 컴퓨터의 주소로 이 웹 사이트에 접속을 할 수 있는 것이다.
결론적으로 리액트 앱은 node.js 기반의 웹 서버 위에서 동작하고 있다고 생각하면 되겠다.
웹 서버가 꺼졌으므로 더 이상 접속할 수 없다.
npm start 명령어를 통해 웹 서버를 다시 킬 수 있다.
결론적으로 리액트는 es module system을 사용하지만, 그렇다고 우리가 이전에 배웠던 commonJS module system을 몰라도 된다는 얘기는 아니다.
JSX
JSX는 리액트의 컴포넌트를 만드는 데에 아주 유용하게 사용되는 문법이다.
컴포넌트를 사용할 때에는 모듈을 불러와준 다음에, 마치 태그를 사용하듯이, 컴포넌트 이름을 입력해주면 된다.
Error : MyHeader(...) : Nothing was returned from render.
MyHeader가 아무것도 리턴하고 있지 않아서 렌더를 할 수 없다. 이렇게 JSX 문법에서 컴포넌트를 만들기 위해서는 무엇이가는 리턴해주어야 한다.
App 컴포넌트가 자식으로 포함하고 있지 않은 컴포넌트들은 아무리 많이 만들어도 화면에 나타나지 않는다. 왜냐하면, 리액트 앱이 작동하는 방식에 대해 다루어 볼 때, index.js에서 id가 root인 요소를 찾고, 그 요소에 app이라는 컴포넌트를 불러와서 렌더하는 것을 확인했었다. 결론적으로 app이라는 컴포넌트가 최상위 부모가 되게 되는 것이고, 그 부모가 포함하지 않은 자식은 화면에 나타날 수 없게 되는 것이다.
닫힘 규칙
: <div.> 처럼 여는 태그가 있으면, </div.> 처럼 닫는 태그가 있어야 한다는 것이다. 닫는 태그를 없애면 바로 에러가 발생한다. 이럴 때 활용하기 좋은 것은 <image /.>와 같이 태그를 열자마자 닫아주는 것이다. self closing이라고 한다.
최상위 태그 규칙
: 최상위 태그 : 다른 모든 태그를 가장 바깥에서 감싸고 있는 가장 바깥의 태그
최상위 태그를 지우면 바로 에러가 발생하게 된다.
JSX의 표현식은 반드시 하나의 부모를 가져야 한다. JSX로 컴포넌트를 만들어서 return 하려면
반드시 하나의 최상위 태그로 다른 모든 것들을 묶어줘야 한다.
만약에 최상위 태그로 안 묶고 싶다면?
React.fragment라는 기능을 이용해서 최상위 태그를 대체할 수 있는데, React.fragment는 React의 기능이기 때문에, 우리가 import를 통해서 React를 불러와줘야 한다. 사용하기 전에.
<React.Fragment>
<MyHeader />
<header className="App-header">
<h2>안녕 리액트 {name}</h2>
</header>
</React.Fragment>
React.Fragment라는 태그를 열어서 우리가 최상위 태그에 넣고 싶지 않은 태그를 감싸주면 된다. React Fragment 를 작성하기가 귀찮다면 빈 칸으로 <>으로 열고 </> 닫아서 빈 태그를 작성해주면 된다.
리액트의 기능을 이용하지 않는 컴포넌트에서는 굳이 리액트를 import 하지 않아도 상관 없다.
원래 html에서는 class라고 클래스를 지정해주었는데, JAS에서는 class라는 단어가 스크립트 예약어이기 때문에 못 쓴다. 그래서 className이라고 쓴다고 알아두면 되겠다.
뭔가 한 것이 없는데 전부 중앙 정렬이 되어 있다.
App.css를 열어보면, App이라는 클래승에 text-align이 center로 되어있는 것을 볼 수가 있다.
그렇기 때문에, 리액트 컴포넌트에서는 import 키워드와 경로를 사용하여 이런 식으로 css를 불러다가 사용할 수가 있고, CSS는 이런 요소들에 적용된다.
css 파일을 사용하는 방식 말고도 인라인 스타일링 방식을 사용할 수 있다.
인라인 스타일링 방식 : css 파일을 사용하지 않고 객체를 사용하는 방식
JSX에 자바스크립트의 값을 사용하는 방법
<h2 style={style.h2}>안녕 리액트 {name}</h2>
<h2 style={style.h2}>안녕 리액트 {1 + 2}</h2>
<h2 style={style.h2}>안녕 리액트 {"문자열"}</h2>
const func = () => {
return "func";
}
// 중략 ..
<h2 style={style.h2}>안녕 리액트 {func()}</h2>
<h2 style={style.h2}>안녕 리액트 {false}</h2>
<h2 style={style.h2}>안녕 리액트 {[]}</h2>
숫자나 문자가 아닌 것을 넣으면 렌더가 되지 않는다. JSX의 중괄호 안에는 값을 포함할 수 있지만, 숫자나 문자열만 포함할 수 있다.
{number}는 : {number % 2 === 0 ? "짝수" : "홀수"}
State
State라는 것만으로도 리액트가 전부 설명된다고 해도 과언이 아닐 정도로, 굉장히 중요한 개념이다.
리액트에서 말하는 상태(State)는, 컴포넌트가 갖는 테마처럼 계속 값이 바뀔 동적인 데이터이고, 상태를 바꾸는 등의 관리는, 이것을 가진 컴포넌트가 직접 관리하게 된다.
useState : 상태를 사용하겠다라는 메서드를 추가적으로 import를 해주어야 한다.
배열의 비구조화 할당..?
count는 상태값으로 사용되고, setCount는 count라는 상태를 변화시키는 상태 변화 함수로써 사용하게 된다.
const [count, setCount] = useState(0);
useState 메서드를 호출하면서 넘겨준 이 인자인 0은, 우리가 count라는 상태를 만들 때 초깃값으로 사용된다.
결론적으로, 지금 화면에 표시되는 것이 실시간으로 계속 바뀐다는 건, count state가 바뀔 때마다, counter라는 함수가 반환을 다시한다고 생각할 수 있다.
App 컴포넌트가 Counter 컴포넌트를 호출하고, 반환 받은 html을 화면에 표시하는 것이기 때문에, counter 컴포넌트가 리턴을 다시 하는 것이다. 화면을 새로 그리는 것이다. 이런 것을 리렌더라고 한다.
이것을 통해 알 수 있는 것?
컴포넌트는 자신이 가진 State(상태)가 변화하면, 화면을 다시 그려 리렌더를 한다. Counter 함수가 다시 호출된다고 생각하면 되겠다.
리액트는 여러 개의 스테이트를 하나의 컴포넌트가 가져도 전혀 문제가 되지 않는다.
Props
컴포넌트에 데이터를 전달하는 가장 기본적인, 효율적인, 강력한 방법인 Props에 대해 알아보겠다.
App 컴포넌트에서 Counter 컴포넌트에게 Counter의 초깃값을 0이 아닌 App 컴포넌트가 전달하는 값을 써라.라는 명령을 내리고 싶다면 어떻게 해야 할까?
<Counter initialValue={5} />
이것을 Prop이라고 하는데 이런 식으로 초깃값을 전달할 수 있다.
부모 컴포넌트인 App 컴포넌트에서 자식 컴포넌트인 카운터 컴포넌트에게 어떤 값을 이름을 붙여서 전달하는 이 방식을 Prop이라고 부를 수 있는데, 그러면 이렇게 전달되는 데이터들을 복수형으로 이야기하면 Props라고 이야기를 할 수 있다. Props는 우리가 이전에 객체를 배울 때 이야기 했었던 Properties의 줄임말이다.
Counter 컴포넌트에서는 App 컴포넌트에서 보내준 값을 매개변수를 통해 받아올 수 있다.
비구조화 할당을 통해 받을 수도 있다.
변수 입력을 잊을 수도 있는데, defaultProps를 통해 해결할 수 있다.
이렇게 defaultProps 기능을 이용하면 전달받지 못한 Props의 기본 값을 설정해서 에러를 방지할 수 있다.
Props로는 정적인 데이터 뿐만 아니라 동적인 데이터 또한 전달할 수 있다.
리액트의 컴포넌트는 부모가 내려주는 Props가 변경되면 다시 렌더를 하게 된다. 그래서 리렌더가 일어난다고 생각해주면 된다.
부모 요소의 State가 Counter Component의 State가 바뀌게 되면, 자식 요소인 OddEvenResult 컴포넌트도 계속 리렌더가 되는 것을 확인할 수 있다.
리액트의 컴포넌트는
- 본인이 관리하고 본인이 가진 스테이트가 바뀔 때마다 리렌더가 되고,
- 나에게 내려오는 props가 바뀔 때마다 리렌더가 되고,
- 둘 다 아니어도 내 부모가 리렌더가 되면 나도 리렌더가 된다.
props는 뭐든 전달할 수 있기 때문에 컴포넌트 자체도 전달할 수 있다.
<Container>
<div>
<MyHeader />
<Counter {...counterProps} />
</div>
</Container>
Container 컴포넌트의 자식으로 배치된 이 요소들은 Container 컴포넌트의 Children이라는 Prop으로 전달되게 된다. 그래서 Children에 JSX 요소가 전달됐고, 결론적으로 Children을 값처럼 활용해서 div를 밖에 두고 감싸서 이렇게 보이는 것을 확인할 수 있다.
리액트의 Props 기능은 컴포넌트를 다른 컴포넌트의 Prop으로 전달할 수 있다.
State와 Props는 이 두 개 자체로 리액트라고 생각해도 무방할 정도로 굉장히 중요하고, 또 입문자가 처음 접했을 때 굉장히 당황스러울 수 있는 개념들인데, 여기까지 잘 이해했다면 리액트에 소질이 있는 사람일 가능성이 있다. 따라서 다음에 나오는 내용들은 더 쉽고 재미있게 사용할 수 있을 것이다.
해당 게시글은 인프런 - <한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지> 강의 내용을 기반으로 작성되었음을 알립니다.
'Coding > 언더독 레볼루션 (UnderDog Revolution)' 카테고리의 다른 글
웹 서비스, 알고 개발하자! | 1차시 ~ 3차시 (1) | 2024.02.12 |
---|---|
리액트 스터디 : JavaScript 응용 - 1 (Truthy & Falsy, 삼항 연산자, 단락회로 평가, 조건문 업그레이드, 비 구조화 할당, Spread 연산자) (0) | 2023.01.21 |
리액트 스터디 : Node.js 기초 (0) | 2023.01.20 |
리액트 스터디 : JavaScript 기본 - 2 (변수, 상수, 자료형, 형 변환, 연산자, 조건문) (1) | 2023.01.15 |
리액트 스터디 : JavaScript 기본 - 1(변수, 상수, 자료형, 형 변환, 연산자, 조건문) (0) | 2023.01.15 |