리액트 문서로 기초 다지기
🌹생각
이번에 기술면접을 준비하면서 느낀 점은, 기초가 제대로 안 잡혀 있는 듯한 느낌이 들었다. 아예 대답 못할 것 같은 것들도 많았고, 알고 있는 것들도 말로 표현 못하겠고... 코드를 짜고 뭔가를 만들어 내는 게 중요하지 않을까 했었는데, 이론을 제대로 알지 못하고 쓰니 어떤 상황에서 어떤 문법을 써야 하는지 제대로 생각해내지 못하는 것 같았다.
그래서 리액트 문서를 보면서 다시 기초를 제대로 잡고, 추가적으로 공부를 진행하려고 한다!!
이 글은 리액트 문서와 블로그 등 정리한 것을 기록하고 연습해 본 글입니다~!
🌹목록
- 컴포넌트 생성 및 중첩하기
- JSX로 마크업 작성하기
- 스타일 추가하기
- 데이터 표시하기
- 조건부 렌더링
- 리스트 렌더링하기
- 이벤트에 응답하기
- 화면업데이트하기
- Hook 사용하기
- 컴포넌트 간에 데이터 공유하기
**는 추가로 공부하고 주소 연결할 것
컴포넌트 생성 및 중첩하기
리액트 앱은 컴포넌트로 구성됩니다. 컴포넌트는 고유한 로직과 모양을 가진 UI의 일부입니다. 컴포넌트는 버튼만큼 작을 수도 있고 전체 페이지만큼 클 수도 있습니다.
React 컴포넌트는 마크업을 반환하는 자바스크립트 함수입니다.
import React from "react";
function MyButton() {
return (
<>
<button>I'm button</button>
</>
);
}
export default MyButton;
이제 MyButton을 선언했으므로 다른 컴포넌트 안에 중첩할 수 있습니다.
import "./App.css";
import MyButton from "./components/button";
function App() {
return (
<>
<h1>welcome My study</h1>
<MyButton />
</>
);
}
export default App;
<MyButton />이 대문자로 시작하는 것을 주목해 주세요. 이것이 바로 React 컴포넌트임을 알 수 있는 방법입니다. React 컴포넌트의 이름은 항상 대문자로 시작해야 하고 HTML 태그는 소문자로 시작해야 합니다.
export default 키워드에 대한 것이 알고 싶다면?
맨 아래의 링크 참고 @@
JSX로 마크업 작성하기
- JSX(Javascript Syntax eXtension)는 Javascript 확장한 문법이다.
- JSX는 리액트로 프로젝트를 개발할 때 사용되므로 공식적인 자바스크립트 문법은 아니다.
- 브라우저에서 실행하기 전에 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환된다.
1. 반드시 부모 요소 하나가 감싸는 형태여야 한다.
(=> virtual DOM에서 컴포넌트 변화를 감지할 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙이 있기 때문이다.
2. 자바스크립트 표현식
JSX 안에서도 자바스크립트 표현식을 사용할 수 있다. 자바스크립트 표현식을 작성하려면 JSX 내부에서 코드는 { }로 감싸주면 된다.
(자바스크립트 표현식은 값을 생성하는 코드의 조각으로, 실행될 때 단일 값을 반환합니다.)
3. if문 (for문) 대신 삼항 연산자(조건부 연산자) 사용
if구문과 for 루프는 JS 표현식이 아니기 때문에 JSX 내부 자바스크립트 표현식에서는 사용할 수 없다.
그렇기 때문에 조건부에 따라 다른 렌더링 시 JSX 주변 코드에서 if문을 사용하거나, {} 안에서 삼항 연산자(조건부 연산자)를 사용한다.
참고
https://goddaehee.tistory.com/296
스타일 추가하기
React에서는 className으로 CSS 클래스를 지정합니다. 이것은 HTML의 class 어트리뷰트와 동일한 방식으로 동작합니다.
<img className="avatar" />
그 다음 별도의 CSS 파일에 해당 CSS 규칙을 작성합니다.
/* In your CSS */
.avatar {
border-radius: 50%;
}
데이터 표시하기
JSX를 사용하면 자바스크립트에 마크업을 넣을 수 있습니다. 중괄호를 사용하면 코드에서 일부 변수를 삽입하여 사용자에게 표시할 수 있습니다.
return (
<h1>
{user.name}
</h1>
);
JSX 어트리뷰트에서 따옴표 대신 중괄호를 사용하여 “자바스크립트로 이스케이프(Escape Into JavaScript)” 할 수도 있습니다. 예를 들어 className="avatar"는 "avatar" 문자열을 CSS로 전달하지만 src={user.imageUrl}는 자바스크립트 user.imageUrl 변수 값을 읽은 다음 해당 값을 src 어트리뷰트로 전달합니다.
(=> 즉, src={user.imageUrl}처럼 중괄호를 쓰면 자바스크립트의 변수를 읽거나 계산된 값을 HTML 속성으로 전달할 수 있습니다. 이를 "JavaScript로 이스케이프"한다고 표현합니다. )
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
JSX 중괄호 안에 문자열 연결과 같이 더 복잡한 표현식을 넣을 수도 있습니다.
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};
export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}
조건부 렌더링
React에서 조건문을 작성하는 데에는 특별한 문법이 필요 없습니다. 일반적인 자바스크립트 코드를 작성할 때 사용하는 것과 동일한 방법을 사용합니다. 예를 들어 if 문을 사용하여 조건부로 JSX를 포함할 수 있습니다.
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
더욱 간결한 코드를 원한다면 조건부 삼항 연산자를 사용할 수 있습니다. 이것은 if 문과 달리 JSX 내부에서 동작합니다.
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
else 분기가 필요하지 않으면 더 짧은 && 연산자를 사용할 수도 있습니다.
** 연산자
<div>
{isLoggedIn && <AdminPanel />}
</div>
연습한 예시 코드
import React from "react";
import 정면사진 from "../assets/정면 사진.jpg";
function MyButton() {
const user = {
name: "sara",
imgSize: 90,
};
const greet = "welcme";
return (
<>
<h2>{user.name}</h2>
<img
src={정면사진}
alt={"photo of" + user.name}
style={{
width: user.imgSize,
height: user.imgSize,
borderRadius: "50%",
}}
/>
{user.name === "yuni" ? <button>I'm {greet} button</button> : null} // 조건부 삼항 연산자 코드
{user.name === "yuni" && <button>I'm {greet} button</button>} // && 연산자 코드
</>
);
}
export default MyButton;
리스트 렌더링하기
컴포넌트 리스트를 렌더링하기 위해서는 for 문 및 map() 함수와 같은 자바스크립트 기능을 사용합니다.
const favorite = [
{ title: "running", isWorkout: true, id: 1 },
{ title: "fitness", isWorkout: true, id: 2 },
{ title: "swim", isWorkout: true, id: 3 },
{ title: "food", isWorkout: false, id: 4 },
];
return(
<ul>
{favorite.map((items) => (
<li
key={items.id}
style={{ color: items.isWorkout === true ? "red" : "black" }}
>
{items.title}
</li>
))}
</ul>
)
이런 식으로
컴포넌트 내에서 map() 함수를 사용하여 제품 배열을 <li> 항목 배열로 변환해도 되고 함수를 바깥으로 빼도 됩니다.
const list = favorite.map((items) => (
<li
key={items.id}
style={{ color: items.isWorkout === true ? "red" : "black" }}
>
{items.title}
</li>
));
return(
<ul>{list}</ul>
)
<li>에 key 어트리뷰트가 있는 것을 주목하세요. 목록의 각 항목에 대해, 형제 항목 사이에서 해당 항목을 고유하게 식별하는 문자열 또는 숫자를 전달해야 합니다. React는 나중에 항목을 삽입, 삭제 또는 재정렬할 때 어떤 일이 일어났는지 알기 위해 key를 사용합니다.
이벤트에 응답하기
컴포넌트 내부에 이벤트 핸들러 함수를 선언하여 이벤트에 응답할 수 있습니다.
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
onClick={handleClick}의 끝에 소괄호(())가 없는 것을 주목하세요! 이벤트 핸들러 함수를 호출하지 않고 전달만 하면 됩니다. React는 사용자가 버튼을 클릭할 때 이벤트 핸들러를 호출합니다.
**function handleClick()과 const handleClick = () => {}의 차이점
화면업데이트하기
컴포넌트가 특정 정보를 “기억”하여 표시하기를 원하는 경우가 종종 있습니다. 예를 들어 버튼이 클릭된 횟수를 세고 싶을 수 있습니다. 이렇게 하려면 컴포넌트에 state를 추가하면 됩니다.
먼저, React에서 useState를 가져옵니다.
이제 컴포넌트 내부에 state 변수를 선언할 수 있습니다.
import { useState } from 'react';
function MyButton() {
const [count, setCount] = useState(0);
// ...
useState로부터 현재 state (count)와 이를 업데이트할 수 있는 함수(setCount)를 얻을 수 있습니다. 이들을 어떤 이름으로도 지정할 수 있지만 [something, setSomething]으로 작성하는 것이 일반적입니다.
버튼이 처음 표시될 때는 useState()에 0을 전달했기 때문에 count가 0이 됩니다. state를 변경하고 싶다면 setCount()를 실행하고 새 값을 전달하세요. 이 버튼을 클릭하면 카운터가 증가합니다.
같은 컴포넌트를 여러 번 렌더링 하면 각각의 컴포넌트는 고유한 state를 얻게 됩니다. 각 버튼을 개별적으로 클릭해 보세요.
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
각 버튼이 고유한 count state를 “기억”하고 다른 버튼에 영향을 주지 않는 방식에 주목해 주세요.
Hook 사용하기
use로 시작하는 함수를 Hook이라고 합니다. useState는 React에서 제공하는 내장 Hook입니다. 다른 내장 Hook은 API 레퍼런스에서 찾아볼 수 있습니다. 또한 기존의 것들을 조합하여 자신만의 Hook을 작성할 수도 있습니다.
Hook은 다른 함수보다 더 제한적입니다. 컴포넌트(또는 다른 Hook)의 상단에서만 Hook을 호출할 수 있습니다.
컴포넌트 간에 데이터 공유하기
이전 예시에서는 각각의 MyButton에 독립적인 count가 있었고, 각 버튼을 클릭하면 클릭한 버튼의 count만 변경되었습니다.
하지만 데이터를 공유하고 항상 함께 업데이트하기 위한 컴포넌트가 필요한 경우가 많습니다.
( 여러 컴포넌트가 동일한 상태를 공유하고 실시간으로 업데이트해야 하는 경우에 상태를 중앙에서 관리하고, 이 상태가 변경될 때마다 관련 컴포넌트들이 이를 반영하도록 해야 합니다. 이럴 때 Context API, Recoil, Redux와 같은 상태 관리 도구가 유용하게 사용됩니다. )
어떤 경우가 있을까?? =>
사용자 인증 상태 관리 - 로그인/로그아웃 상태를 여러 컴포넌트에서 공유해야 하는 경우입니다. 예를 들어, 로그인 여부에 따라 사용자에게 다른 UI를 표시해야 할 때, 로그인 상태를 여러 컴포넌트에서 참조할 수 있습니다.
장바구니 상태 - 사용자가 상품을 장바구니에 추가하거나 제거하는 상태를 여러 컴포넌트에서 공유해야 합니다. 예를 들어, 장바구니에 추가된 상품의 수나 총합을 여러 곳에서 표시해야 할 때입니다.
테마 및 스타일 관리 - 다크 모드와 라이트 모드를 선택하는 상태를 여러 컴포넌트에서 공유해야 하는 경우입니다. 예를 들어, 사용자가 테마를 변경하면 UI의 모든 컴포넌트가 이 변경을 반영해야 합니다.
두 MyButton 컴포넌트가 동일한 count를 표시하고 함께 업데이트하려면, state를 개별 버튼에서 모든 버튼이 포함된 가장 가까운 컴포넌트로 “위쪽”으로 이동해야 합니다.
이 예시에서는 MyApp입니다.

export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... we're moving code from here ...
}
그 다음 공유된 클릭 핸들러와 함께 MyApp에서 각 MyButton으로 state를 전달합니다. 이전에 <img>와 같은 기본 제공 태그를 사용했던 것처럼 JSX 중괄호를 사용하여 MyButton에 정보를 전달할 수 있습니다.
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
이렇게 전달한 정보를 props라고 합니다. 이제 MyApp 컴포넌트는 count state와 handleClick 이벤트 핸들러를 포함하며, 이 두 가지를 각 버튼에 props로 전달합니다.
마지막으로 부모 컴포넌트에서 전달한 props를 읽도록 MyButton을 변경합니다.
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
새로운 count 값은 각 버튼에 prop로 전달되므로 모든 버튼에는 새로운 값이 표시됩니다. 이를 “state 끌어올리기”라고 합니다. state를 위로 이동함으로써 컴포넌트 간에 state를 공유하게 됩니다.