1. JS 기본 문법
변수 선언
- let, const → 블록 단위 스코프
- var → 블록을 벗어나도 접근 가능 (함수 스코프) → 사용을 지양하는 추세
Rest 연산자 (...)
- 함수 매개변수, 객체 또는 배열에서 남은 요소들을 하나의 변수로 그룹화
// 함수 매개변수로 사용
function sum(...numbers) {
return numbers.reduce((acc, current) => acc + current, 0);
}
// 객체에서 특정 속성을 제외한 나머지 속성들 추출
const { password, ...sampleObj } = person;
Null 병합 연산자 (??)
- 좌변이 null이나 undefined일 경우에만 우변 값 사용
- || 연산자와의 차이: ||는 모든 falsy 값을 평가하지만, ??는 null과 undefined만 평가
const itemsPerPage = preferences.itemsPerPage ?? 10;
ES6 모듈 시스템
// 내보내기
export const add = (a, b) => a + b;
export default function multiply(x, y) { return x * y; }
// 가져오기
import multiply, { add } from './math.js';
import { conflictFunction as function1 } from './module1';
import * as MathFunctions from './math.js';
Promise와 Async/Await
- Promise: 비동기 작업의 완료 또는 실패를 나타내는 객체
const myPromise = new Promise((resolve, reject) => {
// 비동기 작업 후 resolve 또는 reject 호출
});
- Async/Await: 비동기 코드를 동기적으로 작성할 수 있게 해주는 문법
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error("오류 발생:", error);
}
}
- Async 함수는 항상 Promise를 반환
- await는 Promise가 해결될 때까지 함수 실행을 일시 중단
2. React 기초
SPA(Single Page Application)
- SPA는 하나의 HTML 페이지로 이루어진 애플리케이션
- React, Vue, Angular가 대표적인 SPA 구현 도구
MPA vs SPA
- MPA(Multi Page Application):
- 여러 페이지로 구성된 애플리케이션
- 페이지 이동 시 서버에서 새 HTML 파일을 생성하여 전송
- SSR(Server Side Rendering) 방식 사용
- SPA(Single Page Application):
- 단일 페이지로 구성된 애플리케이션
- 최초 로딩 후 페이지 전환 없이 필요한 데이터만 서버에서 받아와 동적으로 화면 갱신
- CSR(Client Side Rendering) 방식 사용
SPA 동작 원리
- 요청: 클라이언트가 특정 UI 요소를 클릭하면 서버에 데이터만 요청
- 응답: 서버는 HTML 대신 JSON 형태의 데이터만 전송
- 렌더링: 클라이언트의 JavaScript가 받은 데이터로 DOM을 업데이트하여 UI 변경
라우팅(Routing)
- Hashed Routing:
- URL의 해시(#) 부분을 활용한 라우팅 기법 http://localhost:3000/#about
- 해시 이후 부분은 서버로 전송되지 않고 클라이언트에서만 처리
- Browser Routing:
- 깔끔한 URL 구조를 제공하는 방식 www.sample-homepage.com/about
- React에서는 사용자 경험을 위해 주로 Browser Routing 방식을 채택
React 프로젝트 생성 방법
- CRA(Create React App):
yarn create react-app [프로젝트명] - Vite:
- CRA보다 훨씬 빠른 속도
yarn create vite [프로젝트명] --template react- Vite가 최근 트렌드
3. React 컴포넌트(Components)
컴포넌트 유형
- 함수형 컴포넌트
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
- 클래스형 컴포넌트
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
부모-자식 컴포넌트 관계
- 부모 컴포넌트: 다른 컴포넌트를 포함하는 컴포넌트
- 자식 컴포넌트: 다른 컴포넌트 안에 포함되는 컴포넌트
function Child() { //자식
return <div>나는 자식입니다.</div>;
}
function App() { //부모
return <Child />;
}
4. Props
Props 특성
- 읽기 전용(Read-only)
- 컴포넌트 간 데이터 전달
Props 사용법
function Mother() {
const name = '홍부인';
return <Child motherName={name} />; // motherName으로 props 전달
}
function Child(props) {
return <div>{props.motherName}</div>;
}
Props Children
- 컴포넌트 태그 사이에 넣은 내용을 props.children으로 접근 가능:
function User(props) {
return <div>{props.children}</div>;
}
function App() {
return <User>안녕하세요</User>;
}
Props 추출 방법
- 구조 분해 할당(Destructuring) (보통 이 방식으로 많이 사용)
function Todo({ title, body, isDone, id }) {
return <div>{title}</div>;
}
- 기본값 설정(Default Arguments):
function Welcome({ name = "Guest" }) {
return <h1>Welcome, {name}!</h1>;
}
5. State
State 사용법
- useState Hook을 사용하여 state 생성
const [name, setName] = useState("김할아");
setName("박할아"); // 상태 업데이트
State 응용 예시
function App() {
const [name, setName] = useState("길동이");
function onClickHandler() {
setName("누렁이");
}
return (
<div>
{name}
<button onClick={onClickHandler}>버튼</button>
</div>
);
}
입력 필드와 State
const App = () => {
const [inputValue, setInputValue] = useState("");
const onChangeHandler = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input type="text" onChange={onChangeHandler} value={inputValue} />
<p>입력값: {inputValue}</p>
</div>
);
};
Props Drilling
- 여러 계층의 컴포넌트를 거쳐 데이터를 전달하는 것
- 너무 깊은 경우 상태 관리 라이브러리(Redux, Recoil 등) 사용 고려
6. 불변성(Immutability)
리액트에서 불변성 유지하기
- 배열/객체 수정 시 직접 변경하지 않고 전개 연산자(...)로 복사 후 수정
// 올바른 방법
setDogs([...dogs, "시고르자브르종"]);
// 잘못된 방법 (불변성 위반)
items.push(items.length + 1);
setItems(items);
7. 컴포넌트와 렌더링
컴포넌트의 본질
- 컴포넌트:
- 리액트의 핵심 빌딩 블록
- UI 요소를 표현하는 최소 단위
- 선언적 프로그래밍 방식으로 UI 구성
명령형 vs 선언형 프로그래밍
- 명령형(DOM 직접 조작): 절차를 일일이 코드로 작성
- 선언형(React): UI를 선언하면 React가 내부적으로 절차 수행
렌더링 과정
- 트리거(Triggering): 렌더링 요청
- 렌더링(Rendering): 컴포넌트가 UI 생성
- 커밋(Commit): 결과를 실제 DOM에 반영
렌더링 발생 조건
- 첫 리액트 앱 실행 시
- 상태(state) 변경 시
- props 변경 시
- 부모 컴포넌트 리렌더링 시
8. DOM과 Virtual DOM
DOM(Document Object Model)
- 웹페이지의 요소들을 트리 형태로 표현
가상 DOM(Virtual DOM)
- 실제 DOM의 복사본으로 메모리에 객체 형태로 저장
DOM 조작 과정
- 변경 전/후 두 버전의 가상 DOM 생성
- Diffing: 두 가상 DOM 비교하여 변경점 파악
- 재조정(Reconciliation): 변경된 부분만 실제 DOM에 적용
Batch Update
- 여러 변경사항을 모아서 한 번에 DOM에 적용
브라우저 렌더링(페인팅)
- 스타일 계산: HTML/CSS 분석하여 스타일 결정
- 레이아웃: 요소 위치와 크기 계산
- 페인팅: 실제 화면에 그리기
9. 반복 컴포넌트 리팩토링
map() 함수 사용
- JavaScript의 map() 메서드를 사용하여 반복되는 JSX 요소를 동적 렌더링으로 변환
- 예시: 여러 채소 컴포넌트를 단일 매핑으로 변환:
const vegetables = ["감자", "고구마", "오이", "가지", "옥수수"];
return (
<div className="app-style">
{vegetables.map((vegetableName) => {
return (
<div className="square-style" key={vegetableName}>
{vegetableName}
</div>
);
})}
</div>
);
복잡한 데이터 처리
- 객체 배열(더 복잡한 데이터 구조) 다루기
- 반복적인 UI 요소를 처리하기 위한 별도 컴포넌트 생성
- 사용자 데이터 예시:
function User(props) {
return (
<div>{props.user.age}살 - {props.user.name}</div>
);
}
const App = () => {
const users = [
{ id: 1, age: 30, name: '송중기' },
{ id: 2, age: 24, name: '송강' },
{ id: 3, age: 21, name: '김유정' },
{ id: 4, age: 29, name: '구교환' },
];
return (
<div className="app-container">
{users.map((user) => {
return <User user={user} key={user.id} />;
})}
</div>
);
};
10. 상태 관리 및 사용자 상호작용
useState를 활용한 CRUD 구현
const [users, setUsers] = useState([/* 초기 사용자 */]);
const [name, setName] = useState('');
const [age, setAge] = useState('');
// 사용자 추가
const addUserHandler = () => {
const newUser = {
id: users.length + 1,
age: age,
name: name,
};
setUsers([...users, newUser]);
};
// 사용자 삭제
const deleteUserHandler = (id) => {
const newUserList = users.filter((user) => user.id !== id);
setUsers(newUserList);
};
컴포넌트 추출
- 중복을 줄이기 위한 커스텀 버튼 컴포넌트 생성:
function CustomButton(props) {
return <button onClick={props.onClick}>{props.children}</button>;
}
키(Key) 사용
- React가 리스트 항목을 효율적으로 관리하기 위한 식별자
{
users.map((user) => {
return <User user={user} key={user.id} handleDelete={deleteUserHandler}/>;
})
}
학습하며 어려웠던 점과 배운 점
map vs forEach 차이점
- 반환 값
- map(): 원본 배열의 각 요소를 변환한 새로운 배열을 반환합니다.
- forEach(): 반환 값이 없습니다 (undefined).
- 목적
- map(): 배열의 각 요소를 변환하여 새 배열을 만드는 데 사용합니다.
- forEach(): 단순히 배열을 순회하며 각 요소에 대해 함수를 실행하는 데 사용합니다.
- React에서의 사용
- map()은 JSX에서 배열 데이터를 컴포넌트 리스트로 변환할 때 특히 유용합니다.
- forEach()는 새 배열을 반환하지 않기 때문에 JSX 내에서 직접 사용하기에는 적합하지 않습니다.
DOM이 트리 구조인 이유
<html>
<body>
<div>
<h1>Hello</h1>
<p>World</p>
</div>
</body>
</html>
위 HTML 코드의 트리 구조:
html
└── body
└── div
├── h1
│ └── "Hello"
└── p
└── "World"
리액트의 개발 방식
- 리액트 개발자는 선언형 방식으로 개발하지만, 내부적으로는 명령형으로 동작
- 가상 DOM을 사용하여 렌더링 최적화
이론적 개념 이해
- DOM, 컴포넌트, 렌더링과 같은 개념적인 부분은 코딩보다 이론적 이해가 필요
- 이번 학습을 통해 이러한 개념을 더 명확히 확립할 수 있었음
'프론트 JS 뿌시기' 카테고리의 다른 글
| Tailwind CSS 테일윈드 V4 업데이트 (1) | 2025.05.27 |
|---|---|
| 프론트 js 처음부터 뿌시기 5월 - 2 <React 및 Redux : 최적화> (1) | 2025.05.11 |
| 프론트 js 처음부터 뿌시기 4월 - 2 <JavaScript 기본 문법과 함수 정리> (0) | 2025.05.11 |
| 프론트 js 처음부터 뿌시기 4월 - 1 (1) | 2025.04.26 |