React는 UI(사용자 인터페이스) 제작을 도와주는 자바스크립트 라이브러리로, cdn
등을 활용해 간단히 사용할 수 있다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>리액트 맛보기</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script> // 👈 react
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script> // 👈 react-dom
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
// 🖕 babel : JSX문법을 → JavaScript로 변환해주는 "Babel"
</head>
<body>
<div id="app"></div>
// 👇 babel을 연결했기 때문에 → HTML 문서에서도 "JSX" 문법을 사용해 작성할 수 있다!
<script type="text/babel">
const appEl = document.getElementById("app");
const root = ReactDOM.createRoot(appEl);
const Greeting = () => <h1>Hello World</h1>;
root.render(<Greeting />);
</script>
</body>
</html>
전통적인 웹 개발에서 HTML, CSS, JavaScript는 각각 구조, 스타일, 동작을 담당하는 역할을 해왔다. 하지만 몇가지 한계점을 맞닿드리며 "REACT"가 탄생하게 되었다.
React는 Facebook에서 대규모 애플리케이션의 복잡한 UI를 효율적으로 구현하고 관리하기 위해 개발되었다.
React는 선언형 프로그래밍 방식을 따라, 웹 페이지의 모습을 선언
한다.
예를 들면 '로그인했을 때만 사용자 이름을 보여줘' 👈 처럼!
로그인 상태에 따라 사용자의 이름을 어떻게 보여줄지는 React가 결정한다.
선언적 프로그래밍은 컴퓨터 프로그래밍의 한 종류로,
컴퓨터에게 무엇을(What) 해야 하는지
알려주는 방식이다.
쉽게 말하면 컴퓨터에게 "무엇을 해야 하는지"에 대한 목표만 정해주고, 해당 과정은 프로그래밍 언어나 프레임워크가 처리하도록 하는 프로그래밍이다.
function Greeting() {
return <div>Hello World</div>
}
JSX
문법을 사용해 생성한다.<Greeting />
createElement
함수 호출을 보다 직관적으로 표현해주는 문법적 편의를 제공한다.// 컴포넌트 선언
function SomeComponent() {
return <h1>{3 + 5}</h1>
}
// 엘리먼트 생성
const someElement = <SomeComponent />
// 컴포넌트의 재사용
function AnotherComponent() {
return (
<div>
<SomeComponent />
<SomeComponent />
</div>
)
}
HTML Tag를 비슷하게 사용할 수 있어, 웹 개발자에게 친숙하고 읽기 쉽다.
JSX 내에서 JavaScript 표현식을 중괄호 {}
안에 사용할 수 있다.
이를 통해 Data Binding이나 반복문 처리 등이 가능하다.
function App() {
const name = "Young"
return <div>Hello~! My name is {name}.</div>
}
JSX를 사용해 React 컴포넌트를 → React 엘리먼트로 만들 수 있다.
이를 통해 UI를 구조화하고 재사용할 수 있다.
JavaScript
의 확장 문법인 JSX
문법을 이해하지 못하기 때문에 Babel과 같은 트랜스파일러(컴파일러)를 통해 JSX
문법 → JavaScript
로 변환하는 과정이 필요하다.npm
으로 설치한 패키지들이 저장되어 있는 디렉토리/
)에서 바로 접근 가능한 Asset들을 담아두는 디렉토리App.js
: 프로젝트 루트 컴포넌트App.css
: 루트 컴포넌트에서 사용할 스타일들을 담아 둔 스타일시트 파일index.js
: 루트 컴포넌트를 HTML document에 연결시켜주는 코드가 작성된 JS파일index.css
: 프로젝트 전반에 걸쳐 사용할 스타일들 담아 둔 스타일시트 파일그 외
: 그 외 파일들은 테스트와 디버깅을 위한 파일로, 대부분 사용하지 않는다.git
을 사용한 소프트웨어 버전 관리에서 제외할 파일과 폴더를 적어두는 파일package-json
을 통해 설치된 패키지들의 상세 정보를 담고 있는 파일props
이라고 한다.props
는 읽기 전용으로, 수정이 불가하다.props
를 잘 사용하면 컴포넌트의 재사용성과 유연성이 크게 증가한다.props
값이 변경되면 자식 컴포넌트는 리렌더링된다.function Greeting(props) {
return <h1>안녕하세요, {props.name}님!</h1>;
}
function App() {
const someName = "철수"
return (
<div>
<Greeting name="지수" />
<Greeting name={someName} />
</div>
);
}
children
이라고 하는 특별한 props가 존재한다.children
으로 props가 전달된다.function App() {
return <Card>안녕하세요?</Card>
}
function Card(props) {
return <div>{props.children}</div>
}
리액트 공식문서에 따르면 state는 'A Component's Momory'라고 한다.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 초기값 0
const increment = () => {
setCount(count + 1); // count를 1 증가시키는 함수
};
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={increment}>증가</button>
</div>
);
}
useEffect
은 함수형 컴포넌트에서 부수효과(side effects)를 처리하기 위한 Hook이다.
useEffect(() => {
// 부수 효과를 수행하는 코드를 작성한다.
return () => {
// 컴포넌트가 언마운트되기 전, 또는 업데이트되기 전에 실행되는 '정리(clean-up)' 코드를 작성한다.
};
}, [dependencies]); //부수 효과를 유발할 의존성들을 추가한다.
그럼 어떤 부수효과(side effects)를 처리할까?
종속성(의존성) 배열을 제공하지 않으면, 컴포넌트가 마운트되거나 업데이트될때 마다 실행된다.
useEffect(() => {
console.log('컴포넌트가 마운트되거나 업데이트될 때마다 실행됩니다.');
});
빈 배열([]
)로 제공하면, 컴포넌트가 마운트될 때 한번만 실행된다.
useEffect(() => {
console.log('컴포넌트가 마운트될 때 한 번만 실행됩니다.');
}, []);
종속성 배열에 특정 값을 할당하면, 해당 특정 변수가 변경될 때만 실행된다.
useEffect(() => {
console.log(`변수가 변경될 때만 실행됩니다: ${variable}`);
}, [variable]);
컴포넌트가 언마운트되거나 업데이트가 되기 전에 필요한 정리 작업용 함수로도 사용할 수 있다.
예를 들어 구독 해제나 타이머를 제거하는 작업을 들 수 있다.
useEffect(() => {
const timer = setTimeout(() => {
console.log('이 코드는 타이머에 의해 실행됩니다.');
}, 1000);
return () => {
clearTimeout(timer); // 컴포넌트가 언마운트되거나 업데이트되기 전에 타이머를 제거합니다.
};
}, []);
🔥 불변성(Immutability) : 데이터가 생성된 후 수정되지 않는 성질
React에서 상태를 변경할 때는 반드시 항상 새로운 객체나 배열을 생성해 업데이트 해야한다.
👉 React는 상태 불변성을 유지함으로써 이전 상태와 새 상태를 효과적으로 비교하기 때문이다.
➕ 추가
새 요소를 배열에 추가할 때는 스프레드 연산자(...)를 사용해 기존 배열을 복사하고 새 요소를 추가한다.
const [items, setItems] = useState(['사과', '바나나']);
const addItem = (item) => {
setItems([...items, item]);
};
➖ 제거
특정 요소를 제거할 때는 filter 함수를 사용해 해당 요소를 제외한 새 배열을 생성한다.
const [items, setItems] = useState(['사과', '바나나']);
const removeItem = (targetItem) => {
setItems(items.filter(item => item !== targetItem));
};
✔️ 수정
특정 요소를 수정할 때는 map 함수를 사용해 해당 요소만 업데이트된 새 배열을 생성한다.
const [items, setItems] = useState(['사과', '바나나']);
const updateItem = (targetItem, newItem) => {
setItems(items.map(item => item === targetItem ? newItem : item));
};
객체의 속성을 업데이트할 때는 객체 전개 연산자({...})를 사용해 객체를 복사하고, 특정 필드를 업데이트한다.
const [user, setUser] = useState({ name: '지수', age: 20 });
const updateUser = (newValues) => {
setUser({ ...user, ...newValues });
};