본 글은 React 공식문서를 정리 한 글입니다. 
더 자세한 내용은 https://react.dev/을 참고하시길 바랍니다.

 

빠른 시작에서는 React의 개념 중 80퍼센트를 대략적으로 설명한다.

  • How to create and nest components (컴포넌트 생성과 중첩)
  • How to add markup and styles (마크업,스타일 추가)
  • How to display data (데이터 표시)
  • How to render conditions and lists (조건과 목록 랜더링)
  • How to respond to events and update the screen (이벤트 응답과 화면 업데이트)
  • How to share data between components (컴포넌트 간 데이터 공유)

1. 컴포넌트 생성과 중첩

React는 컴포넌트를 기초로 만들어진다. 컴포넌트는 로직과 외형을 갖는 UI의 일부이며 버튼처럼 작을수도, 전체 페이지만큼 클 수도 있다.

React 컴포넌트는 마크업을 반환하는 JavaScript이다.

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}

 

Mybutton 이라는 컴포넌트를 선언한 이후 다른 컴포넌트에 중첩(삽입)할 수 있다.

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );

 

React 컴포넌트의 이름은 항상 대문자로 시작해야하며 HTML 태그는 소문자여야 한다. 이를 통해 컴포넌트를 구별 가능하다.

2. JSX로 마크업 작성

위에서 쓰여진 구문을 JSX라고 한다. 선택사항이지만 대부분의 React 프로젝트에서는 편의를 위해 JSX를 사용한다. 로컬개발에 권장되는 모든 도구는 기본적으로 JSX를 지원합니다.

 

JSX는 HTML보다 엄격하다. <br>로 쓰던 태그도 <br /> 와 같이 태그를 닫아야 한다. 또한 컴포넌트는 여러 JSX 태그를 반환할 수 없다. 그렇기에 <div> ... </div> 나 <> ... </> 와 같은 빈 태그로 하위 태그들을 공유된 상위부모 태그안에 감싸야한다.

function AboutPage() {
  return (
    <>
      <h1>About</h1>
      <p>Hello there.<br />How do you do?</p>
    </>
  );
}

 

JSX로 포트할 HTML가 많을 시 온라인 컨번터를 사용할 수 있다.

3. 스타일 추가

React에서는 className으로 스타일을 추가할 수 있다. 이는 HTML의 class 속성과 동일한 방식으로 작동한다.

<img className="avatar" />

 

이미지 태그에 className를 추가 한 다음 별도의 css파일에 css 규칙을 작성한다.

/* In your CSS */
.avatar {
  border-radius: 50%;
}

 

React은 css 파일을 추가하는 방법을 규정하지 않는다. 가장 간단한 경우 <link>태그를 통해 가능하다. 빌드 툴이나 프레임워크를 사용하는 경우 해당 사용서를 참조하여 프로젝트에 css 파일을 추가해야한다.

3. 데이터 표시

JSX를 사용하면 JavaScript에 마크업을 넣을 수 있습니다. 중괄호를 사용해 JavaScript로 “escape back” 하여 코드의 일부 변수를 포함하고 사용자에게 표시할 수 있습니다.

return (
  <h1>
    {user.name}
  </h1>
);

 

또한 JSX 속성에서 “escape into JavaScript” 할 수도 있지만 따옴표 대신 중괄호를 사용해야 합니다.

예를 들어 className= "avatar" 는 "avatar"를  css 클래스인 문자열로 전달한다. 하지만 src={user.imageUrl} 는 user.imageUrl 의 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
        }}
      />
    </>
  );
}

 

위의 예시중, style={{}} 태그는 특별한 문법이 아니라 JSX 중괄호 안의 일반 객체이다. 스타일이 JavaScript 변수에 따라 달라지는 경우 style 속성을 사용할 수 있다.

4.  조건부 렌더링

React에는 조건 작성을 위한 특별한 구문이 없다. 대신 일반 JavaScript 코드를 작성할 때  사용하는 기술과 동일하게 사용하게 된다. 예를 들어 IF 조건부 구문을 JSX 안에 사용할 수 있다.

let content;
if (isLoggedIn) {
  content = <AdminPanel />;
} else {
  content = <LoginForm />;
}
return (
  <div>
    {content}
  </div>
);

 

보다 간결한 코드를 선호 하는 경우 ? 연산자를 사용할 수 있다. IF와 달리 JSX 내부에서 작동한다.

<div>
  {isLoggedIn ? (
    <AdminPanel />
  ) : (
    <LoginForm />
  )}
</div>

 

다른 분기가 필요하지 않은 경우 더 짧은 논리 구문인 && 를 사용할 수도 있다.

<div>
  {isLoggedIn && <AdminPanel />}
</div>

 

이러한 모든 접근 방법은 조건부로 속성을 지정하는 데에도 작동한다. 위 JavaScript 구문 중 일부에 익숙하지 않은 경우 언제든지 IF..else를 사용할 수 있다.

 

5.렌더링 목록

for 루프 및 배열 map()기능 과 같은 JavaScript 기능을 사용하여 구성 요소 목록을 렌더링한다. 예를 들어, 다음과 같은 제품 배열이 있다고 가정한다.

const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];

 

컴포넌트 내에서 map() 함수를 사용하여 제품 배열을 <li> 항목 의 배열로 변환할 수 있다.

const listItems = product.map(product => 
	<li key={product.id}>
    	{product.title}
    <li/>
);

return (
  <ul>{listItems}</ul>
);

 

어떻게 <li> 태그가 key 속성을 가지는 지 주의해라. 목록 각 항목에 대해 동위 항목 중에서 해당 항목은 고유하게 식별하는 문자열이나 숫자를 전달해야 한다. 일반적으로 key는 데이터베이스 ID와 같은 데이터에서 가져와야 한다. React은 나중에 항목을 삽입, 삭제 또는 재정렬할 경우 어떤 일이 발생했는지 확인하기 위해 key를 사용한다.

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

export default function ShoppingList() {
  const listItems = products.map(product =>
    <li
      key={product.id}
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'
      }}
    >
      {product.title}
    </li>
  );

  return (
    <ul>{listItems}</ul>
  );
}

6. 이벤트 응답

컴포넌트 내부에 이벤트 핸들러 함수를 선언하여 이벤트에 응답할 수 있다.

function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );

onClick={hadleClick} 끝에 괄호가 없다는 점을 주의해라. 이벤트 핸들러 함수를 호출하지 마라 : 전달하기만 하면된다. 유저가 버튼을 누를 때 React가 이벤트 핸들러를 호출할 것이다. 

7. 화면 업데이트

종종 컴포넌트가 일부 정보를 "기억"하고 표시하도록 하려는 경우가 있다. 예를 들어 버튼을 클릭한 숫자를 계산하고 싶을 수도 있다. 이를 구형 하려면 컴포너트에 상태를 추가해야한다. 먼저 useState 를 가져온다.

import { useState } from 'react';

 

이제 컴포넌트 내에서 상태 변수를 선언할 수 있다.

function MyButton() {
  const [count, setCount] = useState(0);
  // ...

 

 

useState으로부터 두가지를 가질 수 있다 : 최신 상태 (count) 그리고 이를 업데이트할 수 있는 함수 (setCount). 이름은 무엇이든 지정할 수 있지만 관례로 [something, setSomething] 의 형식으로 쓴다.

 

처음 버튼이 표시될 때, count는 0 일 것이다. 왜냐하면 useState()를 통해 0를 전달하였기 때문이다. 상태를 변경하려면 setCount()를 호출하고 새로운 값을 전달하면 된다. 밑의 버튼을 클릭하면 카운터가 증가 할 것이다.

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

 

React은 컴포넌트 함수를 다시 호출한다. 이때 count 는 1일 것이다. 그 후 2가 될 것이다.

만약 같은 컴포넌트를 여러개 렌더링 한다면 각각 고유한 상태를 갖는다. 그렇다면 각 버튼을 따로 클릭해야한다. 

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 상태를 기억하는 지, 다른 버튼에 영향을 주지 않는지 주의하자.

8. Hooks 사용

use로 시작하는 이름의 함수를 Hooks라고 부른다. useState는 React이 제공하는 내장 Hooks이다. API reference에서 내장 Hooks에 대한 정보를 살펴볼 수 있다. 기존 Hooks을 결합하여 자신만의 Hooks을 작성할 수도 있다. 

Hooks은 다른 함수들 보다 제한적이다. 컴포넌트(또는 다른 Hook) 상단에서만 Hook를 호출할 수 있다. 만약 useState를 조건문이나 반복문에 사용하고 싶다면 다른 컴포넌트를 추출하여 넣어야한다. 

9. 컴포넌트 간 데이터 공유

이전 예에서 각각의 My button은 독립적인 count를 가지고 있었다. 그리고 각 버튼을 클릭할 때 클릭한 버튼에 대한 count만 변경되었다.

그러나 종종 컴포넌트 간의 데이터를 공유하고 같이 업데이트 해야 할 필요가 있다. 두 My button 컴포넌트를 모두 동일하게 표시하고 함께 업데이트 하려면 상태를 개별 버튼의 "위쪽", 각 버튼들이 포함된 가장 가까운 컴포넌트로 이동해야한다. 

이제 두 버튼 중 하나를 클릭하면 MyApp안의 count가 변경되어 MyButton 안의 두 count가 변경된다. 이를 코드로 구현하면 이와 같다.

먼저 상태를 Mybutton에서 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으로 보낸다. 이전에 <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라고 한다. 이제 컴포넌트에는 count(상태)와 handlerClick(이벤트핸들러)가 MyApp에 포함되어 있으며 두 가지 모두 각 버튼의 props로 전달된다. 마지막으로 상위 컴포넌트에서 전달한 props를 MyButton이 읽도록 변경한다.

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}

 

버튼을 클릭하면 onClick 핸들러가 실행된다. 각 버튼의 onClick props은 MyApp 안의 handleClick 으로 설정되어있으므로 내부 코드가 작동된다. 해당 코드는 setCount(count + 1)를 호출하고 count 상태 값들을 증가시킨다. 새로운 count 값은 props로 각 버튼에 전달되고 유저들은 새로운 값을 볼 수있다. 이를 “lifting state up”라고 부른다. 상태를 위로 이동시켜 컴포넌트간의 데이터 공유를 할 수 있다.

import { useState } from 'react';

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>
  );
}

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}

 

+ Recent posts