[ 3D Web : Front & Back_Next.JS ]
Next.JS의 렌더링이 동작하는 원리.
∇ Front & Back _ Next.JS : Next.JS는 어떻게 렌더링이 이루어질까
목 차
1. NextJS?
2. Next.JS란 React 기반의 프레임워크
3. Pre-Rendering
4. SSR & CSR
5. SSG
6. ISR
7. 서버 컴포넌트 & Hydration
8. Next.JS의 웹 서버는??
9. 정리.
Ⅰ. NextJS란?
◎ Next.JS는 CSR 방식의 JS라이브러리인 React.js를
SSR(Server-side-Rendering) 방식으로 구현할 수 있도록 도와주는 프레임워크입니다.
Ⅱ. NextJS란 React 기반의 프레임워크.
§ React.js는 기본적으로 CSR 방식을 사용하는데,
SSR 방식을 사용하고 싶다면 개발자가 직접 환경을 코드로 구성해줘야 합니다
[ 이것 때문에, React로 개발한 포폴 페이지를, 깃페이지로 배포할 때 애먹고 netlify 사용한 나쁜 기억이..;]
★ 위에서 말한 바와 같이, Next.JS는 직접 환경을 개발자가 구성할 필요 없이,
SSR, SSG 방식을 쉽게 사용할 수 있도록 도와주는 React.JS 기반의 프레임워크입니다.
🩻 Next.js !== 'SSR'
※ Next.js는 "SPA" 이며 "SSG"를 기본으로 사용하고, SSR을 임의대로 사용 가능합니다.
★ Next.js는 기본적으로 SSG를 사용하기 때문에,
'빌드' 시점에서만 'SSR(서버-사이드)'에서 pre-render한 파일들을 보내주고
그 이후에는 'CSR'로 페이지를 이동하는 것 !!
★ SSR을 사용하는 경우, 필요한 요청시에 추가적인 리소스를 불러오게 됩니다.
◇ "결론적으로는, Next.js는 CSR을 사용하여 페이지 이동을 처리합니다."
== 필요한 경우에만, 서버에 추가적인 데이터를 요청합니다.
== SSR 방식을 사용하더라도, 페이지 이동 시마다 HTML*JS 파일을 전체적으로 요청해서
다시 불러오는 것이 아니며, 필요한 데이터의 업데이트 요소만 수행하게 됩니다.
==>> 빠른 페이지 전환과 효율적인 네트워크 사용이 가능한 이유!!
📌 Next.js가 가지고 있는 가장 강력한 장점은 Pre-rendering과 CSR의 장점을 모두 사용할 수 있게 해준다는 것
Ⅲ. Pre-Rendering.
🩻 Next.js는 렌더링을 할 때 기본적으로 pre-rendering(사전 렌더링)을 수행합니다.
* '사전-렌더링' 이란, "서버단"에서 DOM요소드을 한번에 Build한 뒤에, HTML 문서를 렌더링 하는 것을 뜻합니다.
⚗️또 하나의 중요한 개념 == "Hyedration"
-> "Hydration"이란, 서버단에서 미리 렌더링한 HTML에 JS코드를 결합하여서
"이벤트"가 동작할 수 있도록 만드는 과정을 말합니다.
but, 이러한 과정이 모두 SSR인 것은 아닙니다.
⚗️pre-rendering을 하는 방법은 SSG와 SSR로 나뉘며, 둘의 차이는 "HTML을 생성하는 시기"에 있습니다 !
- "SSG" : '빌드 시에 HTML'을 만들고, 각각의 요청이 들어올 때 재사용합니다.
- "SSR" : 각각의 요청이 들어올 때 HTML을 만듭니다.
++기본적으로, SSG가 SSR보다 높은 성능을 가지기 때문에,
SSG를 사용하는 것을 Next,JS에서 권장하고 있습니다.
Ⅳ. SSR & CSR
🩻 SSR과 CSR의 개념 비교.
◎ SSR [ Server - Side - Rendering ]
:: 서버 쪽에서 렌더링 준비를 끝마친 상태로, 클라이언트단으로 전달하는 방식.
★ 중요한 포인트!
:: 렌더링 될 준비를 끝마친 상태로, HTML 응답을 클라이언트 단으로 보낸다는 것!
[ 받아온 값을 가지고 브라우저는 바로 페이지를 렌더링합니다 ]
?? "브라우저가 페이지를 렌더링을 바로 한다" 의 의미는??
:: '브라우저'가 말하는 렌더링의 의미는 HTML * CSS *JS 파일을 서버에서 받아와서
파싱한 뒤 결과물을 화면에 그려내는 과정입니다.
<-> 서버사이드 렌더링에서의 '렌더링'과의 의미는 좀 다름.!
?? 서버 사이드에서의 렌더링.
== 서버 사이드 렌더링에서의 렌더링은
"HTML 파일 내에 내용이 있느냐 없느냐" 입니다.
== 내용이 있다면, 렌더링이 된 것 !
=>> 서버에서 받아온 HTML 파일 내에 내용이 모두 들어 있으므로
브라우저는 바로 페이지를 렌더링하게 됩니다.
[UX적으로, 유저는 바로 페이지를 볼 수 있게 된다는 장점]
==>> 완벽한 HTML을 넘겨 받은 후, 렌더링한 이후에 JS파일을 다운 받습니다.
[브라우저에서 JS파일을 실행시키면, 페이지에서 상호작용까지 가능해짐]
+ ▶ JS파일을 파싱하기 전에, 렌더링되어 보여진 HTML상에서 사용자가 인터렉션을 하게 되면,
이 이벤트를 기억하고 있다가 JS가 성공적으로 컴파일 된 후 기억하고 있던 조작을 실행시키게 됩니다.
★ 장단점.
* 장점
- 현재 접근하는 페이지의 HTML만 전달받기 때문에 초기 렌더링 시간이 빠름.
- 각 페이지마다 HTML이 있기 때문에 검색엔진에 유리.
* 단점.
- 화면 전환 시마다 새로운 HTML을 가져오기 때문에 깜빡임 이슈 있음.
- 서버에 비교적 부담을 주게 됨.
◎ CSR [ Client - Side - Rendering ]
:: SSR과 달리, 렌더링이 클라이언트 단에서 일어납니다.
=>> 서버는 요청을 받으면 클라이언트쪽으로 HTML * JS 파일을 보내줍니다.
=>> 클라이언트는 이것을 받아서 렌더링을 시작합니다.
📌 참고
처음 접속 시에는 HTML과 JS 파일이 우선적으로 보내지고,
그 후 CSS나 폰트 파일, 이미지 파일들 같은 리소스들은 추가적으로 로드됩니다.
★ CSR은 마지막 4단계에 왔을 때 유저가 화면을 볼 수 있고, 상호작용을 할 수 있습니다.
Why : 서버가 HTML 파일을 줄 때, 렌더 준비가 되지 않은 파일이기 때문. !
[ = HTML 파일 안에는 아무런 내용이 없다는 것 ]
->> JS 파일을 받아서 실행을 시킨 뒤에야 만들어지게 됩니다.
- index.js 상에 React.createElement라는 메서드가 존재하는데
이 메서드가 HTML 태그를 생성합니다.
- index.html 파일의 바디 태그 안에는 <div id="root"></div>와 같이
div 태그 하나만 존재하고 안에는 아무 내용이 없습니다.
[ == 아무것도 없으므로, 유저는 처음에 빈 화면을 볼 수 밖에 없음. ]
=>> 브라우저가 추가적으로 JS파일을 다운받고 실행할 때
index.js에서 root 태그를 화면에 그려주게 됩니다.
★ 장단점.
* 장점
- 부드럽고 빠른 화면 전환 ( 페이지 깜빡임 이슈 없음)
- 서버에 부담이 적음.
* 단점.
- 초기 렌더링 시에 모든 리소스를 다운 받아야 하기 때문에 렌딩 시간이 오래 걸림.
- HTML이 단 하나로, 메타태그가 하나뿐이기 때문에 SEO에 불리.
☆ ☆ ☆
: SSR은 index.html 파일 속에 화면에 그려내야 할 코드들이 이미 작성되어 있기 때문에
빈 div 태그만 있는 CSR 방식과 달리
브라우저가 HTML을 받은 바로 그 시점에 Viewable 할 수 있는 것입니다.!
🩻 SSR과 CSR의 차이.
1. 웹 페이지의 로딩 시간.
● 첫 페이지 로딩 시간.
- CSR 방식 : HTML, CSS, 모든 스크립트들을 한번에 불러옵니다.
- SSR 방식 : 필요한 부분의 HTML과 스크립트만 불러옵니다.
☆ SSR이 더 빠릅니다.
● 나머지 페이지 로딩 시간.
:: 첫 페이지를 로딩한 후, 사이트의 다른 곳으로 이동하는 등의 동작들.
- CSR 방식 : 이미 첫 페이지 로딩 시 나머지 부분을 구성하는 코드를 받았음으로 빠름. !
- SSR 방식 : 첫 페이지를 로딩한 것처럼,
페이지 이동 시마다 동일하게 미리 그려진 HTML 파일을 보내고 그 이후에 JS를 파싱하는 과정.
☆ CSR이 더 빠릅니다.
2. SEO적인 측면.
- 검색 엔진은 자동화 봇인 '크롤러'로 웹 사이트를 읽어들입니다.
∇ 위에서 설명한 내용에서, CSR은 최초로 불러온 HTMl 파일의 내용이 비어있다고 했습니다.
JS 코드의 내역이 로드된 후에야, 동적으로 root 안의 내용을 채우는 방식이었습니다.
따라서, 웹 크롤러가 인터넷 상을 돌아다니면서 사이트들을 탐문하는 상황이라고 가정하면,
CSR방식의 페이지는 비어있는 root만 노출시킬 수 밖에 없는 것입니다.
웹 크롤러는 정적인 HTML의 내용을 먼저 수집하여 색인하기 때문입니다.
∇ 반면에, SSR 방식의 사이트는 애초에 서버단에서 HTML 내용을 모두 채운 상태로
클라이언트단으로 넘어오기 때문에 크롤러의 데이터 수집에 대응하기 용이합니다. !
3. 서버 측 자원 사용.
※결론적으로 말하면, SSR방식이 서버단 자원을 더 많이 사용합니다.
- HTML의 내용은 이미 받아왔기 때문에 페이지는 그려지지만
- 유저의 상호작용을 위한 데이터가 필요하다면
[브라우저 -> 프론트서버 -> 백엔드 서버 -> DB를 거쳐서 데이터를 가져온 후
브라우저에 데이터가 그려지는 과정]을 반복해야 하기 때문 !
**매번 서버에 요청을 보내기 때문에, 서버 부하 문제가 발생 가능합니다.
🩻 Next.JS에서의 SSR과 CSR.
◎ SSR [ Server - Side - Rendering ]
:: 서버 쪽에서 렌더링 준비를 끝마친 상태로, 클라이언트단으로 전달하는 방식.
- SSR은 유저가 페이지를 요청할 때마다 HTML문서가 생성됩니다.
= 매 요청마다, 서버에 의해 호출디는 getServerSideProps 함수를 사용하는 것이 필요합니다.
◆ 사용되는 상황.
: 항상 최신 상태를 유지해야하는 웹 페이지나, 분석 차트 등등
유저의 요청마다 "동적으로 페이지를 생성"시켜서 다른(최신화된) 내용을 보여주어야 하는 경우에 사용 !
◆ CSR방식을 쓸 때와의 차이점.
: CSR과 SSR방식의 큰 차이에는 "데이터를 불러오는 방식"이 있습니다.
-> 기존 React로 프로젝트를 만들 때는 CSR 방식으로 데이터를 가져올 때 "useEffect"를 사용했다면,
-> Next.JS에서는 "getServerSideProps", "getStaticProps", "getStaticPaths" 등을 활용하여
데이터를 불러옵니다.
◇ getServerSideProps
Next.js는 pre-rendering 중 'getServerSideProps' 함수를 발견하면,
'컴포넌트 함수 호출 하기 전' 에 'getServerSideProps'를 먼저 "호출" 합니다.
√ API 통신을 통해 데이터를 받아온 후, 컴포넌트에 props로 데이터를 전달합니다. => 이 함수는 "매 요청시마다 호출" 되며, "서버단에서 실행" 됩니다.
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`);
const data = await res.json();
return {
props: {
listData: data,
},
};
}
const Main = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
Ⅴ. SSG.(Static-Site-Generation)
※ Next.JS에서는 SSR 보다 SSG가 높은 성능을 가지기 때문에 SSG를 사용하는 것을 권장합니다.
🩻 SSG와 SSR의 차이.
√ SSG는 빌드 시에 HTML이 생성되고, 매 요청마다 " HTML을 재사용 " 합니다.
<->
√ SSR은 매 요청마다 HTML을 생성하기 때문에 응답 속도가 느리고 서버에 많은 부하를 주게 됩니다.
- SSG에서 HTML은 " next build " 명령어를 사용하는 경우에 생성됩니다.
->> 그 후에는 CDN(콘텐츠 전송 네트워크)으로 캐시가 되어지고,
페이지 요청시마다 HTML을 재사용합니다.
🩻 SSG가 사용되는 상황은?
: 주로 마케팅 페이지, 블로그 게시물 등과 같이 '정적'으로 생성된 정보를
"요청시마다 동일한 정보로 반환" 시켜야 하는 경우에 사용됩니다.
◇ getStaticProps.
: Next.js에서 "SSG 방식" 를 사용하여 데이터를 받아오려면 "getStaticProps"를 사용하면 됩니다.
-> 서버-단 에서만 실행되는 함수로 클라이언트-단에서는 실행되지 않습니다.
- 이 함수는 API와 같은 외부 데이터를 받아서 Static Generation 하기 위한 용도이며,
빌드 시에 딱 한번만 호출되어 static file로 빌드됩니다.
export async function getStaticProps() {
const res = await fetch(`https://.../data`);
const data = await res.json();
return {
props: {
listData: data,
},
};
}
const Main = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
이 코드를 보면
"Main" 페이지가 호출되면,
getStaticProps가 먼저 실행되며 axios 통신을 통해서 게시물 리스트를 가져오고
props에 리턴 값을 담아서 Main 컴포넌트에 전달합니다.
§ 이처럼, getStaticProps를 사용해서 build를 하면 사전에 서버에서 API 호출을 통해서 데이터를 담고
그 데이터가 담긴 HTML을 생성하게 됩니다.
◇ getStaticPaths.
ex) 만약 "동적 라우터(Dynamic Route)"를 사용해서 pages/posts/[id].js 라는 파일을 만들었을 때
id값에 따라서 다른 글(데이터)을 보여주고 싶을 때는????
- id가 1인 글을 추가한다면 -> 빌드 시에 id가 1인 post data를 불러와서 pre-render 해야합니다.
만약 id가 2로 바뀐다면, id가 2인 글을 불러와서 렌더를 해줘야 합니다.
▶ 이러한 상황이 page의 " path가 외부 데이터에 의존 " 하는 경우입니다.
-> 이것을 위해서는 getStaticPaths를 사용해서 pre-render가 필요한 path들을 명시해주면 됩니다.
export const getStaticPaths = async () => {
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } },
{ params: { id: '3' } },
],
fallback: true,
};
};
export const getStaticProps = async ({ params }) => {
const id = params.id;
const res = await axios.get(`https://url/${id}`);
return {
props: {
listData: res.data,
},
};
};
const Detail = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
○ 호출 순서 : "getStaticPaths" -> "getStaticProps" -> "Detail"
- getStaticPaths에서 리턴값으로 path에 1,2,3, 페이지 번호를 지정.
- getStaticProps에서 params.id를 읽어서 해당 게시글에 대한 데이터를 가져와 페이지 생성.
- getStaticPaths에서 '정적'으로 지정했기 때문에 1,2,3 페이지는 static file로 생성됩니다.
○ fallback이란,
getStaticPaths 반환 값 중 fallback 값이 있습니다.
fallback은 true | false | blocking을 값으로 가질 수 있습니다.
동적 페이지인 경우, 빌드 시에 생성되지 않은 주소로 사용자가 요청을 보내는 경우가 존재하는데,
이 경우, fallback 값에 따라 다른 대응을 하게 됩니다.
● true.
√ 빌드 시에 생성되지 않은 정적 페이지를 요청하는 경우, "fallback 페이지"를 제공.
√ 서버에서 정적 페이지를 생성하고, 생성되면 사용자에게 해당 페이지를 제공.
● false.
√ 빌드 시에 생성되지 않은 정적 페이지를 요청하는 경우, "404 페이지"를 응답.
● blocking.
√ 빌드 시에 생성되지 않은 정적 페이지를 요청하는 경우,
" SSR 방식으로 제작한 정적 페이지" 를 사용자에게 제공.
√ 이후에 해당 주소로 요청이 들어오면, 정적 페이지를 응답합니다.
* true와 blocking은 정적 페이지를 생성하고 유저에게 제공한다는 부분이 유사하지만,
true는 정적 페이지가 생성되는 동안 fallback 페이지를 제공한다는 점에서 차이!
Ⅵ. ISR.(Incremental - Static - Regeneration)
☆ SSG에 포함되는 개념이며,
SSG와의 차이점은 "설정한 시간마다 페이지를 새로 렌더링" 한다는 점 !!
∇ SSG는 빌드 시점에 페이지를 생성하기 때문에, 데이터가 변경되면 다시 빌드를 진행해야하지만,
ISR은 일정 시간마다 특정 페이지만 다시 빌드하여 페이지를 업데이트 합니다.
🩻 ISR이 사용되는 상황은?
√ '블로그'와 같이 컨텐츠가 동적이지만, 변경의 빈도가 적은 사이트의 경우 ISR을 사용하는 것이 좋습니다.
export const getStaticProps = async ({ params }) => {
const id = params.id;
const res = await axios.get(`https://url/${id}`);
return {
props: {
list: res.data,
},
revalidate: 20,
};
};
const Detail = ({ list }) => {
<ul>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
+ 위에서 언급한 SSG-getStaticProps 사용 방법과 비슷하지만,
revalidate에 명시된 숫자(초단위)마다 페이지가 새로 렌더링 되는 차이점이 있습니다.
Ⅶ. 서버 컴포넌트 & Hydration.
🩻 서버 컴포넌트 [ Server Component ]
√ Next.JS는 따로 명시해주지 않는 한 기본적으로 모든 컴포넌트가 '서버 컴포넌트'입니다.
- 사용자가 페이지에 도달하면, 브라우저가 서버에 요청을 보내게 되고
서버에서 렌더링을 진행한 후에 정적인 HTML을 브라우저로 전달합니다.
- 정적 페이지이기 때문에, JS코드가 포함되지 않은 상태입니다.
[ =이벤트 리스너가 등록되어있지 않은 정적인 상태 ]
따라서 초기에 빠르게 페이지를 렌더링 가능합니다.
export default function TestHeader() {
return (
<div>
<h1>This is a test page.</h1>
</div>
);
}
○ 개발자 도구의 소스 탭
-> Run command(명령어 실행) -Ctrl+Shift+P
-> JavaScript(자바스크립트)검색해서 사용중지를 누르면
자바스크립트 코드 없이 렌더링을 해볼 수 있습니다.
🩻 Hydration.
- 페이지의 요소들이 모두 정적으로 그려지지는 않습니다.
- 아래 예시 코드로 만들어놓은 유저가 버튼을 누르면서 버튼 내부의 카운트가 올라가는 기능처럼
사용자와의 '인터렉션' 이 필요한 컴포넌트들이 많은 것이 현실입니다.
- "useState"를 사용하는 등의 '동적인 컴포넌트'는 반드시 ! 클라이언트 컴포넌트로 만들어줘야 합니다.
☆ 컴포넌트 최상단에, 'use clinet'를 명시하면 클라이언트 컴포넌트로 사용 가능합니다.
++ '리액트 훅'을 사용할 때는 'use client'를 항상 명시해줘야 합니다.
'use client';
import { useState } from 'react';
export default function TestBtn() {
const [count, setCount] = useState(0);
const addCount = () => {
setCount(count + 1);
};
return <button onClick={addCount}>{count}</button>;
}
√ 클라이언트 컴포넌트는 정적인 HTML을 전달받은 이후 아주 빠른 시간 내에 JS코드를 다운받습니다.
- 위의 코드를 보면 button에 이벤트 리스너(addcount)를 연결합니다.
이런 방식으로 리액트에서 사용하는 것처럼, 부드러운 인터렉션을 만들 수 있습니다.
◇ 이 과정을 "Hydration"이라고 합니다.
==> 즉 ! " 단순한 HTML을 '리액트 앱'으로 초괴화 하는 작업 " 을 의미합니다. !
§ 위에서 개발자도구로 JS코드를 멈췄던 것을 다시 해본 뒤 페이지를 새로고침하면
위 사진처럼, 연결한 이벤트 리스터가 적용되지 않는 정적인 컴포넌트 상태로 유지되기 때문에
카운트가 반영되지 않습니다.
▶ 이런 식으로, 하나의 페이지 내에 '서버-컴포넌트'와 '클라이언트-컴포넌트' 를 필요에 맞춰 섞어서 사용함으로써
꼭 필요한 JS만 로드 가능하고, 렌더링 시간을 줄여서 성능 최적화를 쉽게 할 수 있습니다.
Ⅷ. 그렇다면, Next.JS의 웹 서버는 어디에 있을까?
○ 위에서 설명한 SSR(Server-Side-Rendering)의 용어를 보면
서버에서 렌더링 로직을 처리해준다는 것을 알 수 있습니다.
◎ 여기서 포인트는, 우리는 다로 웹 서버를 만든적이 없다는 겁니다.
∇ 따로 구성하지 않았음에도 동작이 가능한 이유
== "Next.jS"가 자체적으로 웹 서버를 가지고 있기 때문입니다.
▷ 서버단에서 실행되는 "getServerSideProps" 나 "getStaticProps" 함수는
Next.js의 (자체)서버로 전달되어 역할을 수행하고 결과 값을 컴포넌트 단에 반환합니다.
▷ 해당 함수들이 사용되는 'pages 폴더' 의 영역은
"서버단과 공유하는 영역" 이며, getServerSideProps 등의 함수는
Next.js의 자체 서버에서 실행 됩니다.
Ⅸ. 정리.
🩻 Next.js의 SSR, SSG, ISR
∇ Next.js의 큰 특징은 'pre-rendering' 방식을 사용하여, 서버에서 미리 HTML 문서를 렌더링. !
∇ SSR와 SSG의 차이는 SSG는 HTMl을 빌드시에 생성하여 재사용하고, SSR은 요청 시마다 생성하는 것 !
∇ ISR은 SSG에 포함되는 개념이며, 설정한 시간마다 페이지를 새로 렌더링한다는 차이.
🩻 상황마다 적절한 렌더링 방식
∇ SEO 적용이 크게 중요하지 않거나, 데이터 pre-rendering이 필요없다면 :: " CSR "
∇ 정적 문서로 충분한 화면이면서, 빠른 HTML 문서 반환이 필요하다면 :: "SSG"
∇ 컨텐츠가 동적이지만 자주 변경되지 않은 경우 :: "ISR"
∇ 매 요청 시 마다 화면이 달라지면서 서버-사이드로 렌더링을 하고자 한다면 :: "SSR"
🩻 Next.js가 Hydration 하기까지의 전체 과정.
1. 서버단에서 요청받은 내역을 pre-rendering 합니다.
2. 서버는 pre-rendering이 끝난 정적인 HTML을 클라이언트로 전달하고, 클라이언트는 이것을 수신합니다.
3. 클라이언트 측에서 렌더링{ render() }
클라이언트는 수신된 정적HTML을 우선 렌더링하고, 인터렉션을 위한 JS 파일을 로드합니다.
4. hydrate() 호출
전달된 HTML에 이벤트 핸들러를 연결.
5. 클라이언트 측 렌더링 완료.
hydrate 과정이 완료되면 클라이언트에서 페이지의 렌더링과 인터렉션을 관리 가능합니다.
'Front_End [JS기반] > React.js + Next.js' 카테고리의 다른 글
[ 3D Web : Front_React.js ] React.JS : React를 구성하는 요소, React 컴포넌트란? (1) | 2024.11.29 |
---|---|
[ 3D Web : Front_React.js ] React.JS : React란? (0) | 2024.11.26 |
[ 3D Web : Front & Back_Next.JS ] Next.JS란 무엇이고, 왜 사용하는걸까 (4) | 2024.11.25 |
[ 3D Web : Front_React.js ] React의 JSX & 컴포넌트 & prop & state (2) | 2024.11.23 |
[ 3D Web : Front_React.js ] React의 동작원리 정리. (1) | 2024.11.21 |