React 기초(a.k.a.클라이언트 렌더링)
2025-12-08
React는 2013년 페이스북이 소개한 SPA(single page application) 솔루션으로, 자바스크립트로 현대적인 웹 애플리케이션을 구축하는 방법을 제공합니다.
Vite(빠르다는 뜻의 프랑스어)는 최신 웹 프레임워크를 위한 현대적인 빌드 도구입니다.
package.json: 모든 서드파티 의존성 목록과 프로젝트 구성vite.config.js: Vite 구성 파일src/App.jsx: React 컴포넌트가 구현되는 파일src/main.jsx: React 진입점(entry point)src/index.css, src/App.css: 스타일 파일모든 React 애플리케이션은 React 컴포넌트를 기반으로 구축됩니다.
JSX만 반환하는 경우 중괄호와 return 문을 생략할 수 있습니다.
React로 구성된 페이지는 컴포넌트 트리(component tree)로 구성됩니다.
JSX(JavaScript XML)는 HTML과 자바스크립트를 강력하게 결합하는 문법입니다.
중괄호 {} 안의 모든 것은 자바스크립트를 보간(interpolation)하는 데 사용할 수 있습니다.
JSX는 HTML보다 자바스크립트에 더 가깝기 때문에 React는 카멜 케이스(camelCase) 명명 규칙을 사용합니다.
class → classNamefor → htmlForonclick → onClickJSX는 개발자가 HTML과 자바스크립트를 섞어서 렌더링되어야 할 내용을 표현할 수 있게 해줍니다.
React에서 리스트 렌더링을 준비하기 위해 배열의 내장 메서드 map()을 사용합니다.
React에서는 배열의 내장 map() 메서드를 사용하여 각 아이템에 대한 JSX를 반환합니다.
const list = [
{
title: 'React',
url: 'https://react.dev/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'Redux',
url: 'https://redux.js.org/',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 1,
},
];
function App() {
return (
<div>
<ul>
{list.map(function (item) {
return <li key={item.objectID}>{item.title}</li>;
})}
</ul>
</div>
);
}리스트의 각 자식은 고유한 key prop을 가져야 합니다.
key는 React가 리스트를 효율적으로 업데이트하는 데 사용id 속성)를 사용해야 함컴포넌트는 애플리케이션의 크기에 따라 확장되어야 하므로, 하나의 컴포넌트를 여러 컴포넌트로 분할해야 합니다.
function App() {
return (
<div>
<h1>My React Stories</h1>
<Search />
<hr />
<List />
</div>
);
}
function Search() {
return (
<div>
<label htmlFor="search">Search: </label>
<input id="search" type="text" />
</div>
);
}
function List() {
return (
<ul>
{list.map(function (item) {
return (
<li key={item.objectID}>
{/* ... */}
</li>
);
})}
</ul>
);
}src/main.jsx 파일에서 App 컴포넌트가 인스턴스화됩니다.
React: React 개발자의 일상적인 업무에 사용React DOM: React 애플리케이션을 네이티브 HTML 세계에 연결React에서는 JSX에서 선언적인 방식으로 핸들러를 추가합니다.
React의 합성 이벤트는 본질적으로 브라우저의 네이티브 이벤트를 감싸는 래퍼(wrapper)입니다.
event.nativeEvent를 통해 접근할 수 있음함수의 반환 값이 아니라 함수 자체를 핸들러에 전달해야 합니다.
Props는 부모 컴포넌트에서 자식 컴포넌트로 정보를 전달하는 수단입니다.
function App() { // 부모 컴포넌트
const stories = [
{ title: 'React', objectID: 0 },
{ title: 'Redux', objectID: 1 },
];
return (
<div>
<List list={stories} /> {/* props 전달 */}
</div>
);
}
function List(props) { // 자식 컴포넌트
return (
<ul>
{props.list.map((item) => (
<li key={item.objectID}>{item.title}</li>
))}
</ul>
);
}Props 객체를 구조 분해하여 더 간결하게 사용할 수 있습니다.
List 컴포넌트에서 Item 컴포넌트를 추출하고 각 아이템을 전달할 수 있습니다.
const List = (props) => (
<ul>
{props.list.map((item) => (
<Item key={item.objectID} item={item} />
))}
</ul>
);
const Item = (props) => (
<li>
<span>
<a href={props.item.url}>{props.item.title}</a>
</span>
<span>{props.item.author}</span>
<span>{props.item.num_comments}</span>
<span>{props.item.points}</span>
</li>
);React State는 변경 가능한(mutable) 데이터 구조입니다.
useState 훅을 사용하여 상태 값을 관리할 수 있습니다.
import * as React from 'react';
const Search = () => {
const [searchTerm, setSearchTerm] = React.useState('');
const handleChange = (event) => {
setSearchTerm(event.target.value);
};
return (
<div>
<label htmlFor="search">Search: </label>
<input id="search" type="text" onChange={handleChange} />
<p>
Searching for <strong>{searchTerm}</strong>.
</p>
</div>
);
};useState는 초기 상태를 인자로 받습니다콜백 핸들러는 컴포넌트 트리 위쪽으로 소통하기 위한 암시적인 수단입니다.
// A: 부모 컴포넌트에서 핸들러 정의
const App = () => {
const handleSearch = (event) => {
console.log(event.target.value);
};
return (
<div>
{/* B: 자식 컴포넌트로 함수 전달 */}
<Search onSearch={handleSearch} />
</div>
);
};
// C: 자식 컴포넌트에서 함수 호출
const Search = (props) => {
const handleChange = (event) => {
props.onSearch(event); // D: 부모로 다시 호출
};
return (
<input onChange={handleChange} />
);
};한 컴포넌트에서 다른 컴포넌트로 state를 이동시키는 과정을 상태 끌어올리기(Lifting State)라고 합니다.
const App = () => {
const stories = [ /* ... */ ];
const [searchTerm, setSearchTerm] = React.useState('');
const handleSearch = (event) => {
setSearchTerm(event.target.value);
};
const searchedStories = stories.filter((story) =>
story.title.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div>
<Search onSearch={handleSearch} />
<List list={searchedStories} />
</div>
);
};State는 항상 그 State에 관심이 있는 모든 컴포넌트가 State를 직접 관리하거나, State를 관리하는 컴포넌트의 하위 컴포넌트로서 정보를 Props로 받아 사용하는 위치에서 관리해야 합니다.
HTML 요소의 value 속성을 활용하여 React의 state를 사용하도록 합니다.
const App = () => {
const [searchTerm, setSearchTerm] = React.useState('React');
return (
<div>
<Search search={searchTerm} onSearch={handleSearch} />
</div>
);
};
const Search = (props) => (
<div>
<label htmlFor="search">Search: </label>
<input
id="search"
type="text"
value={props.search} {/* React state 사용 */}
onChange={props.onSearch}
/>
</div>
);React의 useEffect 훅은 컴포넌트의 생명주기에 사이드 이펙트를 포함하는 것을 용이하게 합니다.
[]: 컴포넌트가 처음 렌더링 될 때만 딱 한 번 호출커스텀 훅은 특정 요구사항에 맞춰 자체적인 훅을 만드는 것입니다.
React 프래그먼트는 렌더링 된 출력에 추가하지 않고 형제 엘리먼트들을 하나의 최상위 엘리먼트로 감쌉니다.
const Search = ({ search, onSearch }) => ( // React.Fragment 사용
<React.Fragment>
<label htmlFor="search">Search: </label>
<input
id="search"
type="text"
value={search}
onChange={onSearch}
/>
</React.Fragment>
);
const Search = ({ search, onSearch }) => ( // 단축 문법 사용
<>
<label htmlFor="search">Search: </label>
<input
id="search"
type="text"
value={search}
onChange={onSearch}
/>
</>
);React children prop을 사용하면 React 컴포넌트들을 서로 합성할 수 있습니다.
const App = () => {
return (
<div>
<InputWithLabel
id="search"
value={searchTerm}
onInputChange={handleSearch}
>
<strong>Search:</strong>
</InputWithLabel>
</div>
);
};
const InputWithLabel = ({
id,
value,
onInputChange,
children,
}) => (
<>
<label htmlFor={id}>{children}</label>
<input
id={id}
type="text"
value={value}
onChange={onInputChange}
/>
</>
);React는 선언형 프로그래밍 접근 방식을 사용하지만, 필요할 때는 명령형 접근 방식을 수행할 수 있습니다.
useRef 훅을 사용하여 DOM 엘리먼트에 직접 접근할 수 있습니다.
const InputWithLabel = ({
id,
value,
onInputChange,
isFocused,
children,
}) => {
const inputRef = React.useRef();
React.useEffect(() => {
if (isFocused && inputRef.current) {
inputRef.current.focus();
}
}, [isFocused]);
return (
<>
<label htmlFor={id}>{children}</label>
<input
ref={inputRef}
id={id}
type="text"
value={value}
onChange={onInputChange}
/>
</>
);
};useRef 훅으로 ref 객체 생성ref는 엘리먼트의 JSX 예약 속성인 ref에 전달useEffect 훅으로 React의 생명주기에 관여ref.current 속성을 통해 엘리먼트에 접근| 버전 | 날짜 | 변경 내용 |
|---|---|---|
| v.20251103 | 2025-11-03 | React 기초 내용 추가 |