Next.js 프로젝트 캠프 3기에 지원하다!
올해 개발팀 인턴으로 근무했엇는데, 그때 Nextjs를 처음 사용해보았다. 인턴기간동안 Nextjs라는 새로운 프레임워크를 활용하여 기획부터 앞으로 실제 서비스 할 사이트를 개발,배포해보았는데 정해진 인턴기간이 있는지라 80%정도 밖에 완성하지 못한게 아쉬웠다. 마침 인턴기간이 끝나는즈음에 시작하는 유데미x스나이퍼팩토리 Next.js 프로젝트 캠프 3기 공고문을 보게되었고, 이 과정을 통해 Next.js 팀 프로젝트를 포트폴리오에 하나 더 추가할 수도 있을것 같고, 사전 직무교육도 해준다니 급하게 업무에 적용하느라 부분부분만 익힌 next를 더 잘 활용할 수 있게 되겠지 하는 생각에 프로젝트 캠프에 지원서를 넣고, 활동을 시작하게 되었다.
# 사전직무교육 1일차
- 자바스크립트의 역사
1일차 오전수업때는 자바스크립트의 역사에 대해 알려주셨는데, 이 부분을 알아둘생각을 못했었던지라 매우 흥미로운 시간이었다.
- 1991년 : 팀 버너스리, 월드와이드웹 & HTML발표
- 1993년 : 모자이크 커뮤니케이션즈가 모자이크 브라우저 출시
- 1994년 : 넷스케이프 커뮤니케이션즈에서 넷스케이프 네비게이터를 출시 (이때 개발된 프로그래밍 언어가 바로 Mocha ➡️LiveScript ➡️오늘날의 JavaScript )
- 1995년 : 마이크로소프트사에서 넷스케이프 네비게이터를 리버스 엔지니어링(고대로 배낀거...) 해서 우리가 얼마전까지 흔하게 사용하던 바로 그 인터넷 익스플로러를 출시함, 점유율을 높이기 위해 윈도우 운영체제에 포함시켜 무료로 배포하였고, 그로인해 넷프케이프 커뮤니케이션즈의 점유율이 큰 폭으로 떨어졌음
- 1996년 : 넷스케이프 커뮤니케이션즈 주도로 컴퓨터 시스템의 표준을 관리하는 비영리 표준화 기구인 ECMA 인터내셔에 자바스크립트의 표준화를 요청, 요청이 받아들여져 ECMAScript규격 제정
- 이후 매년 ECMAScript가 업데이트 되어 규정되었으나 마이크로소프트사는 이미 윈도우, 인터넷 익스플로러 점유율이 90%에 육박했기 때문에 표준 제정에 반발하였고 그로 인해 한동안 ECMAScript 업데이트가 멈춤
- 2008년 : 구글에서 크롬 v8을 출시하면서 마이크로소프트와 모질라재단(넷스케이프)에게 다시 표준을 제정하자고 제안함
- 2009년 : ES5 개발
- 2015년 : ES6 출시 (이후 매년 ES는 업데이트 되고 있다, 하지만 여전히 최신 문법의 기준은 es6)
이러한 역사도 한번쯤은 읽어두면, 혹시모를 면접 대비 질문 하나를 해결할 수 있을것같다.
- 자바스크립트 최신 문법
이후에는 자바스크립트 최신 문법에 관한 수업이 있었다. ES6에서 출시된 문법이며, 수업에 아예 처음 배우는 사람은 없었던것같지만 타입스크립트, 리액트, NEXT 들어가기전에 수업에 중요하고 자주 쓰이는 기본 문법을 한번 싹 정리해주심!
- 템플릿 문자열 : 큰 따옴표나 작은 따옴표 대신 `백틱 기호`로 문자열을 정의
console.log(`따옴표가 있어도"그대로 출력되는 백틱"`);
console.log("따옴표가 있으면\\"그전에는 '이런식으로' 적어야 했다\\"");
let name1 = "철수";
let name2 = "바둑이";
// 템플릿 문자열은 이렇게 백틱 기호안에서 변수의 값을 치환해서 사용할 수 있다.
let str = `${name1}는 ${name2}를 좋아합니다.`;
console.log(str);
const str2 = `백틱을 쓸 수 있게 됨, 10 + 20 = ${10 + 20}`; // 문자열로 취급
console.log(str2);
- 화살표 함수
// 화살표 함수는 식별자가 없으므로, 함수표현식처럼 변수를 생성해줘야 부를 수 있다.
const sum = (num1, num2) => {
return num1 + num2;
}
console.log(sum(10,20));
const sum1 = (num1, num2) => num1 + num2;
const result = sum1(20, 20);
console.log(result);
// 함수 표현식
// 익명함수(anonymouse function)
const sum = function (a, b) {
return a + b;
};
// 기명함수 (named function)
const sum = function sum(a, b) {
return a + b;
};
// 화살표함수, 매개변수가 없을때
const printHello = () => '안녕하세요';
console.log(printHello());
const add = function (n1, n2) {
return n1 + n2;
};
// 매개변수가 1개라면 소괄호도 생략
const add2 = (n1, n2) => n1 + n2;
- 비구조화 할당 : 배열 및 객체에서 값을 추출하여 각 변수에 할당이 가능하다
// 배열에서의 비구조화 할당
const [apple1, banana2, orange3] = ['apple', 'banana', 'orange'];
console.log(apple1); // apple
console.log(banana2); // banana
console.log(orange3); // orange
// 객체에서의 비구조화 할당
// 배열과 다른점은 이름을 내마음대로 짓지 못함, 객체의 속성 이름을 식별자로 사용해야 한다.
const { name, age, gender } = {
name: 'john',
age: 20,
gender: 'male',
};
console.log(name); // john
console.log(age); // 20
console.log(gender); // male
- spread 연산자 : 전개연산자라고도 불리며, 깊은 복사 시에 주로 사용된다
- ... 기호
- 열이나 객체를 펼쳐서 개별 요소나 속성으로 복사하는 데 사용, 기존 데이터 구조를 유지하면서 새로운 데이터 구조를 만들 때 유용하게 사용할 수 있다.
// 배열에서
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]
// 객체에서
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }
const num1 = [10, 20];
const num2 = [30, 40];
// 기존 js 병합
const combinedNum = [num1[0], num1[1], num2[0], num2[1]];
// 위 처럼 병합을 했었는데, 요소가 너무 많다고 하면 아래와 같이 전개연산을 사용한다
const combined = [...num1, ...num2];
console.log(combined); // [1, 2, 3, 4]
TypeScript
타입스크립트는 자바스크립트의 확장한 언어로, 타입을 부여해서 사용한다.
타입스크립트의 기본 자료형 타입 (string, number, boolean, undefined, null...)과 참조 자료형 (object, array, tuple) 등에 관해 알려주셨다.
let str: string = 'hi'; // 변수타입이 문자열
let num: number = 10; // 타입이 숫자
let isLoggedIn: boolean = false; // true or false 논리형
type User = {name: string; age: number}; // object 타입은 객체 타입
const user:User = { name:"mnm", age:111}
let arr: number[] = [1,2,3]; // 타입이 배열인 경우 기본
let arr: Array<number> = [1,2,3]; // 제네릭을 사용해서 표현
// 문자랑 숫자랑 섞인 배열
const mySave:Array<string | number> = [10, 'apple', 'banana', 20];
const mySave:(string | number)[] = [10, 'apple', 'banana', 20];
// 튜플은 배열의 길이와 타입이 고정된 배열
// arr 배열은 총 2개의 요소를 가지는데
// 첫 번째 요소는 문자열이고, 두 번째 요소는 숫자형이다.
const arr:[string, number] = ['apple', 10];
// 그 이외에 정의하지 않은타입,인덱스로 접근하면 무조건 오류
// 모든 타입에 허용, 알지 못하는 타입을 표현해야하는 경우 사용
// 남용은 금지!
let str: any = 'hi';
let num: any = 10;
let arr: any = ['a', 2, true];
// null 타입과 undefined 타입은 특수 자료형 타입
const data:null = null;
const noting:undefined;
기본 타입에 관해 바로 복습할 수 있도록 연습문제들도 준비해 주셔서 좋았음! 수업때 배운 내용을 바로바로 복습할 수 있었다.
함수타입 (옵셔널 파라미터, REST문법이 적용된 매개변수)에 관한 설명도 해주셨고, 연습문제도 다양하게 준비해주셔서 복습하는 데에 많은 도움이 되었다.
// 옵셔널 파라미터는 ? 기호로 표시,
// ? 기호로 표시하면 타입으로 지정한 매개 변수를 생략할 수 있게 된다
function sum(a:number, b:number) { return a + b }
sum(10); // 원래는 인자를 2개 작성하지 않으면 타입스크립트는 오류가 남
// but
function sum(a:number, b?:number) { return a + b }
sum(10); // 이렇게 옵션을 붙여주면, 해당 매개 변수는 옵셔널 파라미터가 되어서 인자 생략 가능.
// 레스트 매개변수 Rest Parameter
// 레스트 매개변수는 배열이기때문에 타입선언시 대괄호를 꼭 넣어야함
function sum(a: number, ...nums: number[]): number {
const totalOfNums = 0;
for (let key in nums) {
totalOfNums += nums[key];
}
return a + totalOfNums;
}
# 사전직무교육 2일 차
타입 오퍼레이터
자바스크립트의 OR(||) 연산자와 AND(&&) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터는 유니언 타입과 인터섹션 타입이 있다.
유니언 타입
유니언 타입은 OR(||) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터(|)로 여러 개의 타입을 결합한 타입
유니언 타입은 연결된 타입 중 1개만 만족하면 된다
- or 연산자 || , 합집합 (a 이거나 b이다)
let value: number | string;
value = 10; // number
value = "hello"; // string
인터섹션 타입
인터섹션 타입은 AND(&&) 연산자와 같은 역할을 하는 타입스크립트 오퍼레이터(*)를 사용하여 2개 이상의 타입을 결합한 타입. 인터섹션 타입은 연결된 타입을 모두 만족해야 함!
- & 교집합, 여러 타입을 모두 만족하는 하나의 타입
- 교집합은 사실상 object에서만 쓰인다. 보통 겹치는 게 없어서 never 공집합이 나오니까!
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
let employee: Person & Employee = {
name: "Alice",
employeeId: 123
};
인터페이스
인터페이스는 객체 타입을 지정할 때 사용하는 문법. 상호 간에 정의한 약속 혹은 규칙.
interface 타입명{
속성:타입,
...
}
interface Person {
name: string;
age: number;
greet(): void;
}
const person: Person = {
name: "Alice",
age: 55,
greet() {
console.log("Hello!");
}
};
person.greet(); // "Hello!"
// 인터페이스를 사용할때 정의되어 있는 속성을 모두 다 꼭 사용하지 않아도 됨, 그걸 옵션 속성이라고 함
interface 인터페이스_이름 {
속성?: 타입;
}
interface Person {
name: string;
age?: number; // age는 선택적으로 포함될 수 있음
}
const person1: Person = { name: "Alice" };
const person2: Person = { name: "Bob", age: 25 };
// readonly 속성은 값을 한 번만 설정할 수 있으며, 이후에는 변경할 수 없음
interface Car {
readonly brand: string;
model: string;
}
const myCar: Car = { brand: "Toyota", model: "Corolla" };
// myCar.brand = "Honda"; // 오류: readonly 속성은 수정할 수 없
또한 인터페이스는 병합과 상속이 가능하다. 병합은 인터페이스를 합치는 것이고, 상속은 기존 인터페이스를 확장하는 방식!
// 병합
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: "Alice",
age: 25
};
// 상속
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
const employee: Employee = {
name: "Bob",
employeeId: 123
};
타입별칭 & 제네릭
// 타입 별칭은 타입에 이름을 붙여서 재사용할 수 있는 기능
// 타입 별칭을 사용하여 문자열과 숫자의 튜플 타입을 정의
type StringNumberPair = [string, number];
const example: StringNumberPair = ["Alice", 25];
// 제네릭
// 제네릭은 타입을 미리 지정하지 않고 사용하는 시점에 타입을 정의해서 쓸 수 있는 문법
// 제네릭은 재사용성이 높은 컴포넌트를 만들때 자주 활용된다.
// 특히 한가지 타입보다 여러가지 타입에서 동작하는 컴포넌트를 생성하는데 사용된다.
// 제네릭을 사용한 함수: T는 함수 호출 시 결정되는 타입 매개변수
function identity<T>(value: T): T {
return value;
}
const numberValue = identity<number>(10); // T는 number로 결정
const stringValue = identity<string>("Hello"); // T는 string으로 결정
리액트 개발 환경 세팅
CRA
- Create React App (CRA)는 리액트 애플리케이션을 빠르고 쉽게 설정할 수 있도록 하는 공식 툴
- 웹팩(Webpack) 기반으로 작동하며, 기본적으로 번들링, 빌드, dev 서버, JSX 컴파일 등을 제공
- 2년 전부터 더 이상 업데이트 되지 않고 있어서 권장하지 않음
npx create-react-app my-app
Vite
- 차세대 빌드 도구로, 빠른 개발 서버와 최적화된 번들링을 제공
- ES 모듈 기반으로 개발 서버에서의 로딩 속도가 빠르며, 핫 모듈 리로딩(HMR)이 CRA보다 훨씬 빠르다
npm create vite@latest
## 빠른 개발 경험과 확장성을 중시하고 꾸준히 업데이트되는 Vite 사용 결정
DOM과 가상 DOM
DOM (Document Object Model)은 웹 페이지 구조를 나타내는 객체 모델. 가상 DOM은 React 같은 라이브러리에서 쓰이는 실제 DOM의 복사본으로, 업데이트를 효율적으로 하기 위해 변경 사항을 최소화한다. 상태가 바뀔 때 실제 DOM을 최적의 방식으로 업데이트해서 성능을 높이는 것.
이외에도
리액트를 왜 사용하는지? 가장 인기 있는 프레임워크이고, 강력한 커뮤니티와 광범위한 생태계가 있으므로,,,, 이런 내용과 바벨과 웹팩, swc, vite에 대한 설명도 해주셨다.
클래스형 컴포넌트 VS 함수형 컴포넌트
클래스형 컴포넌트는 ES6 클래스 문법을 사용하며, this 키워드를 통해 상태와 생명주기 메서드에 접근할 수 있다. 반면, 함수형 컴포넌트는 리액트 버전 16.8 업데이트 때 등장하였는데 함수로 작성되며, 리액트 훅을 사용해서 상태와 생명주기를 관리할 수 있다. 함수형 컴포넌트는 더 간결하고 가독성이 좋으며, 최근에는 대부분의 경우 함수형 컴포넌트가 선호된다.
사전직무교육 3일 차
감기에 걸려서 부득이하게 결석을 했다 ㅠㅠ 병원 갔다 와서 집에서 온라인으로 중간중간 듣긴 했는데 이날은 앞으로 쭉 사용하게 될 TailwindCss에 관한 사용법 등을 알려주신 것 같다. 인턴기간 내내 사용하던 css 프레임워크이기도 하고 강사님이 제공해 주신 강의 노트가 있어서 따로 복습을 하긴 했음.
# 사전직무교육 4일 차
컴포넌트 기본 문법
이벤트
- 리액트에서는 JSX에서 이벤트를 처리하기 위해 camelCase 형식의 속성을 사용한다.
- onClick, OnFocus, onKeyDown, onChange, onSubmit... 등등
function Button() {
const handleClick = () => {
alert("Button clicked!");
};
return <button onClick={handleClick}>Click Me</button>;
}
Props
- Props는 컴포넌트에 데이터를 전달하는 방법이다. 부모 컴포넌트에서 자식 컴포넌트로 값을 전달할 수 있다.
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
<Greeting name="Alice" />;
children
- 컴포넌트의 자식 요소를 나타내며, props.children을 통해 접근할 수 있다.
function Wrapper(props) {
return <div className="wrapper">{props.children}</div>;
}
// 사용 예
<Wrapper>
<p>This is wrapped content.</p>
</Wrapper>;
조건부 렌더링
- 보통 삼항 연산자나 && 연산자를 사용하여 조건부 렌더링을 한다.
function Message({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please log in.</h1>}
</div>
);
}
반복문 렌더링
- 리액트에서는 배열의 map() 메서드를 사용하여 리스트를 렌더링 한다. 각 요소에 고유한 key 속성을 부여해야 한다.
function ItemList({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
// 사용 예
<ItemList items={[{ id: 1, name: "Apple" }, { id: 2, name: "Banana" }]} />;
# 사전직무교육 5일 차
리액트의 핵심인, 리액트 훅에 대해서 배웠다.
리액트 훅은 함수형 컴포넌트에서 상태와 생명주기 기능을 사용할 수 있도록 해주는 함수이다.
useState
- 함수형 컴포넌트에서 상태를 관리할 수 있게 해주는 훅
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useRef
- DOM 요소에 접근하거나 값의 변화를 추적할 수 있는 객체를 반환한다. 상태 업데이트와는 달리 리렌더링을 발생시키지 않는다.
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
useEffect
- 컴포넌트가 렌더링 된 후 부수 효과(예: 데이터 fetching, 구독 등)를 수행할 수 있게 해주는 훅이다.
import React, { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => setData(data));
}, []); // 빈 배열을 두 번째 인자로 주면 컴포넌트가 마운트될 때만 실행
return <ul>{data.map((item) => <li key={item.id}>{item.name}</li>)}</ul>;
}
useLayoutEffect
- useEffect와 유사하지만, DOM 변경 후 브라우저가 그리기 전에 동기적으로 실행된다. 주로 레이아웃 측정에 사용된다.
import React, { useLayoutEffect, useRef } from 'react';
function LayoutEffectExample() {
const boxRef = useRef(null);
useLayoutEffect(() => {
const box = boxRef.current;
console.log('Box width:', box.offsetWidth);
});
return <div ref={boxRef} style={{ width: '50%', height: '100px', backgroundColor: 'lightblue' }}>Hello!</div>;
}
메모제이션
- 메모이제이션(Memoization)은 컴포넌트의 렌더링 성능을 최적화하기 위해 사용되는 기법으로, 이전에 계산된 결과를 기억해 두고 동일한 입력이 주어졌을 때, 다시 계산하는 대신 저장된 결과를 반환한다.
고차 컴포넌트 (Higher-Order Component, HOC)
- 다른 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수이다. 주로 컴포넌트의 로직을 재사용하기 위해 사용된다.
function withLogging(WrappedComponent) {
return function EnhancedComponent(props) {
console.log('Rendering:', WrappedComponent.name);
return <WrappedComponent {...props} />;
};
}
const EnhancedComponent = withLogging(MyComponent);
React.memo
- 함수형 컴포넌트를 메모이제이션하여, 동일한 props로 렌더링할 때 불필요한 재렌더링을 방지한다.
const MyComponent = React.memo(({ count }) => {
console.log('Rendering MyComponent');
return <div>Count: {count}</div>;
});
<MyComponent count={someCount} />;
useCallback
- 함수를 메모이제이션하여, 의존성이 변경되지 않는 한 같은 함수를 반환한다. 주로 자식 컴포넌트에 함수를 props로 전달할 때 사용하여 불필요한 렌더링을 방지한다.
import React, { useCallback, useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount((prev) => prev + 1);
}, []);
return <ChildComponent onClick={handleClick} />;
}
const ChildComponent = React.memo(({ onClick }) => {
console.log('Rendering ChildComponent');
return <button onClick={onClick}>Increment</button>;
});
useMemo
- useMemo는 계산된 값을 메모이제이션하는 훅. 의존성 배열에 있는 값이 변경될 때만 새로운 계산 결과를 생성한다. 비용이 많이 드는 계산의 결과를 저장하여 성능을 최적화하는 데 주로 사용됨
import React, { useMemo, useState } from 'react';
function ExpensiveCalculation({ number }) {
const calculate = (num) => {
console.log('Calculating...');
return num * 2;
};
const result = useMemo(() => calculate(number), [number]);
return <div>Result: {result}</div>;
}
<ExpensiveCalculation number={someNumber} />;
리액트 컨텍스트
useReducer
- 상태 관리에 사용되는 훅으로, 복잡한 상태 로직을 처리할 때 유용하다. useState보다 더 구조화된 방식으로 상태를 업데이트할 수 있다.
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
useContext
- React Context에서 값을 가져오기 위한 훅이다. Context를 선언한 후, useContext를 통해 쉽게 접근할 수 있다.
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div>The current theme is {theme}</div>;
}
zustand
- 간단하고 강력한 상태 관리 라이브러리로, 리액트의 전역 상태를 쉽게 관리할 수 있게 해 준다. 미니멀한 API를 제공하며, 불변성을 유지하면서도 쉽게 상태를 업데이트할 수 있다.
import create from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
function Counter() {
const { count, increment } = useStore();
return (
<div>
Count: {count}
<button onClick={increment}>Increment</button>
</div>
);
}
# 사전직무교육 6일 차
리액트 데이터 통신
- axios라이브러리나 fetch를 사용해서 데이터 통신을 처리하는데, axios는 nextjs와는 잘 맞지 않기도 하고 따로 라이브러리를 설치해서 사용해야 하는 점 때문에 fetch 사용법으로 수업을 한다고 하셨다.
fetch API
- Fetch API는 네트워크 요청을 보내고 응답을 처리하기 위해 사용되는 JavaScript의 내장 함수이다. 리액트에서 외부 API와 데이터를 통신하기 위해 주로 사용된다. 비동기 방식으로 작동하며, Promise를 기반으로 하여 결과를 처리한다.
fetch('https://api.example.com/data')
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // JSON 형태로 변환
})
.then((data) => {
console.log(data); // 받은 데이터 처리
})
.catch((error) => {
console.error('There was a problem with the fetch operation:', error);
});
- 리액트에서의 사용 예시
// 리액트 컴포넌트에서 데이터를 가져올때, 일반적으로 useEffect와 함께 사용하여
// 컴포넌트가 마운트 될 때 API 요청을 수행한다
import React, { useEffect, useState } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((error) => {
console.error('Error fetching data:', error);
setLoading(false);
});
}, []); // 빈 배열을 넣어 컴포넌트가 마운트될 때만 실행
if (loading) return <div>Loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}
데이터통신 실습으로는 TMDB에 가입해서 API를 사용한 실습을 하였다. 충분히 스스로 실습해 볼 수 있는 시간을 주셔서 좋았다. 또한 더미데이터가 있어서 간단하게 실습해 볼 수 있는 사이트도 알려주셨음! https://jsonplaceholder.typicode.com/
리액트 라우터
- 리액트 애플리케이션에서 클라이언트 사이드 라우팅을 구현하는 라이브러리이다. 페이지를 전환할 때 브라우저의 URL을 변경하고, 사용자가 특정 URL에 접근할 때 해당 URL에 맞는 컴포넌트를 렌더링 하여 SPA(Single Page Application)에서 원활한 내비게이션을 가능하게 한다.
- 리액트 라우터는 react-router-dom 패키지를 사용하여 설치 후, BrowserRouter, Route, Switch 등의 컴포넌트를 사용하여 라우팅을 설정한다.
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
## Next.js 기본
- nextjs를 설치하는 것부터 보일러 플레이트를 만드는 것들을 알려주셨다.
npx create-next-app@latest
하이드레이션
Next.js에서 하이드레이션은 서버에서 렌더링 된 HTML이 브라우저에서 완전히 상호작용할 수 있도록 만드는 과정을 말함. 서버에서 미리 HTML을 생성하여 클라이언트에 전달한 후, React가 그 HTML에 이벤트 리스너를 추가하고, 사용자 상호작용에 반응할 수 있게 만드는 작업이 이루어지는데, 이를 하이드레이션이라고 말한다!
주요 과정:
- 서버에서 HTML이 생성되어 클라이언트에 전송된다. (서버 사이드 렌더링)
- 브라우저가 HTML을 받아서 화면에 표시한 후, React가 해당 HTML을 기반으로 자바스크립트를 통해 상호작용 기능을 추가하는 것이 바로 하이드레이션.
# 스트리밍 서버렌더링
Nextjs의 앱 라우팅 방식에서 도입된 기능으로, 페이지의 일부를 서버에서 렌더링 하여 클라이언트로 순차적으로 스트리밍 하는 방식. 하이드레이션을 병렬로 처리한다. 이 방법을 통해 전체 페이지를 한 번에 로딩할 필요 없이, 페이지의 중요한 부분부터 빠르게 사용자들에게 보여줄 수 있다.
Nextjs 프로젝트 캠프 3기 과정은 직무교육은 2주 정도로 짧고, 나머지 4주는 팀 프로젝트를 진행하는데 1주 차 수업을 들으면서 헷갈렸던 개념이나 폴더 구조 잡는 방법 등을 확실히 알 수 있었다. 2주 차 수업은 더욱더 집중해야겠다!!
본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 3기 과정(B-log) 리뷰로 작성 되었습니다.
#유데미 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프 #React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정
댓글