[React] 빠른 시작(Quick Start)

Jeris·2023년 5월 2일
0

React docs translation

목록 보기
1/1
post-thumbnail

컴포넌트 만들기, 중첩(Creating and nesting components)

리액트 앱은 컴포넌트로 구성됩니다. 컴포넌트는 고유의 논리와 형태를 갖는 하나의 UI입니다. 하나의 컴포넌트는 버튼처럼 작을 수도, 전체 페이지처럼 클 수도 있습니다.

리액트 컴포넌트는 마크업(Markup)을 반환하는 자바스크립트 함수입니다.

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

이렇게 만든 MyButton 컴포넌트를 다음과 같이 또 다른 컴포넌트 안에 중첩시킬 수 있습니다.

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

대문자로 시작하는 관례는 그것이 리액트 컴포넌트임을 알려줍니다. HTML 태그는 소문자로 시작해야 하는 반면 리액트 컴포넌트는 대문자로 시작해야 합니다.
결과:

export default 키워드는 파일의 메인 컴포넌트를 명시합니다. 자바스크립트에 친숙하지 않다면 MDN, javascript.info를 참조하면 좋습니다.

JSX로 마크업 작성하기(Writing markup with JSX)

위에서 봤던 마크업 문법을 JSX라고 부릅니다. 필수는 아니지만, 대부분의 리액트 프로젝트들은 편의를 위해 JSX를 사용합니다. 로컬 개발을 위해 추천하는 툴은 모두 별도의 설정과 설치 없이도 JSX를 지원합니다.

JSX는 HTML보다 엄격합니다. <br />같은 태그들은 closing-tag(/)가 필수적입니다. 컴포넌트는 여러 개의 JSX 태그들을 반환할 수도 없습니다. 여러 개의 JSX 태그들을 반환하고 싶다면 그것들을 부모 태그로 감싸야 합니다. 부모 태그는 <div>...</div> 혹은 Fragment(<>...</>) 등이 있습니다.

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

JSX로 변환해야 할 HTML이 너무 많다면, online converter를 활용할 수 있습니다.

스타일 추가하기(Adding styles)

리액트에서 CSS 클래스는 className으로 명시합니다. className은 HTML class attribute와 같은 방식으로 동작합니다.

<img className="avatar" />

이제 CSS 규칙들을 분리된 CSS 파일에 작성합니다.

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

리액트는 CSS 파일을 추가하는 방식을 규약하지 않습니다. 간단한 예시로, HTML에 <link> 태그를 추가해도 됩니다. 어떤 개발 도구나 프레임워크를 사용한다면, 문서를 참조하여 프로젝트에 CSS 파일을 추가하는 방법을 알아보세요.

데이터 표시하기(Displaying data)

JSX는 마크업을 자바스크립트에 포함시킬 수 있게 해줍니다. 마크업 내에서 자바스크립트 문법을 사용하려면 중괄호를 사용해야 합니다. 중괄호를 활용하여 코드에 변수를 포함시키고 사용자에게 데이터를 보여줄 수 있습니다. 예를 들어, 다음 코드는 user.name을 보여줄 것입니다.

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

JSX attributes에서도 자바스크립트 문법을 활용하기 위해 같은 방법을 사용합니다. Attributes 값에 따옴표("")를 사용하는 대신 중괄호를 사용해야 합니다. 예를 들어, 다음 코드는 className="avatar""avatar" 문자열을 CSS class로 전달하지만 src={user.imageUrl}은 자바스크립트 문법으로 user.imageUrl 변수 값을 읽고, src attribute로 그 값을 전달합니다.

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 중괄호style={ } 안에 있을 뿐입니다. 스타일이 자바스크립트 변수들에 의존할 때 style attribute를 사용할 수 있습니다.

조건부 렌더링(Conditional rendering)

조건문을 작성하는 리액트의 독특한 문법은 없습니다. 일반 자바스크립트 코드를 쓰듯이 조건문을 사용합니다. 예를 들어, 조건 부로 JSX를 포함하기 위하여 if문을 사용할 수 있습니다.

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>

이 모든 접근 방식은 조건부로 attributes를 지정할 때도 작동합니다. 이러한 자바스크립트 문법에 익숙하지 않다면 항상 if...else문을 사용하여 시작할 수 있습니다.

배열 렌더링(Rendering lists)

컴포넌트의 배열들을 렌더링하기 위해 for looparray map() function 같은 자바스크립트 기능을 사용해야 합니다.

예를 들어, 다음과 같은 products 배열이 있다고 합시다.

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

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

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

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

<li>key attribute를 갖는 방식에 주목하세요. 배열의 각 항목을 전달할 때, 다른 항목 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열 또는 숫자를 key attribute로 같이 전달해야 합니다. 일반적으로 key는 데이터베이스 ID같은 데이터의 요소로 결정되어야 합니다. 리액트는 추후에 항목들을 삽입, 삭제, 정렬할 때 무슨 일이 일어났는 지 알기 위해 keys를 사용합니다.

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

이벤트에 반응하기(Responding to events)

이벤트 핸들러 함수(event handler function)를 선언하여 컴포넌트 내에서 이벤트에 반응할 수 있습니다.

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

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

onClick={handleClick}에 소괄호 ()가 없다는 점에 유의하세요! 이벤트 헨들러 함수를 호출하지 마세요. 함수 자체를 내려줘야 합니다. 리액트는 사용자가 버튼을 클릭할 때 이벤트 핸들러를 호출할 것입니다.

화면 업데이트하기(Updating the screen)

컴포넌트가 정보들을 "기억"하고 보여주기를 원하는 경우가 많습니다. 예를 들어 버튼이 클릭된 횟수를 세고 싶다면 컴포넌트에 상태(state)를 추가하세요.
1. import useState from React

import { useState } from 'react';

이제 컴포넌트에 상태 변수(state variable)을 선언할 수 있습니다.

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

useState는 현재 상태 count와 상태를 업데이트할 수 있는 함수 setCount 두 값을 반환합니다. 필수는 아니지만 변수명은 관례적으로 [something, setSomething] 형식으로 작성합니다.

버튼이 처음 보여질 때, useState()0을 전달했기 때문에 count0일 것입니다. 상태를 변경하려면 setCount()를 호출하고 새 값을 상태에 전달해야 합니다. 버튼 클릭은 counter를 증가시킵니다.

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

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

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

리액트는 컴포넌트 함수를 다시 호출할 것입니다. 이 때, count1일 것입니다. 다음은 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 상태를 "기억하고" 다른 버튼들에 영향을 주지 않는다는 점에 유의하세요.

훅 사용하기(Using Hooks)

use로 시작하는 함수를 훅(Hook)이라고 합니다. useState는 리액트가 제공하는 내장 훅입니다. 다른 내장 훅들을 API reference에서 확인할 수 있습니다. 존재하는 훅들을 조합하여 커스텀 훅(custom hook)을 작성할 수도 있습니다.

훅 사용은 다른 함수보다 더 제한적입니다. 훅은 컴포넌트 상단에서만 호출할 수 있습니다. useState를 조건이나 루프(loop) 안에서 사용하려면 새로운 컴포넌트를 만들어서 넣고, 그 컴포넌트 안에서 사용해야 합니다.

컴포넌트 사이에서 데이터 공유하기(Sharing data between components)

위의 예시에서 각각의 MyButton은 고유의 독립적인 count를 갖고, 각각의 버튼이 클릭될 때 클릭된 버튼의 count만 변경되었습니다.

그러나 컴포넌트끼리 데이터를 공유하고 함께 업데이트될 필요가 있을 때가 많습니다.

MyButton 컴포넌트들이 같은 count를 보여주고 함께 업데이트 되도록 하려면, 각각의 버튼에서 상태를 "위쪽"으로 이동시켜 모든 버튼을 포함하는 가장 가까운 컴포넌트에 상태를 저장해야 합니다.

MyApp 예시입니다.

이제 두 버튼 중 하나를 클릭하면, MyApp 안의 count가 변경되어 MyButton 안의 두 count가 모두 변경됩니다. 이를 코드로 표현하는 방법은 다음과 같습니다.

먼저, state를 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라고 합니다. 이제 MyApp 컴포넌트는 count 상태와 handleClick 이벤트 핸들러를 포함하고, 이를 각각의 버튼에 props로 전달합니다.

마지막으로 부모 컴포넌트에게 전달 받은 props를 읽기 위해 MyButton을 변경합니다.

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

버튼을 클릭하면 onClick 핸들러가 실행됩니다. 각 버튼의 onClick prop은 MyApp 내의 handleClick 함수로 설정되어 있으므로, handleClick 내부의 코드가 실행됩니다. 이 코드는 setCount(count + 1)을 호출하여 count 상태 변수를 증가시킵니다. 새로운 count 값이 각 버튼에 prop으로 전달되어, 버튼들이 모두 새로운 값을 보여줍니다. 이를 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>
  );
}

Next Steps

지금까지 React 코드를 작성하는 기본적인 방법에 대해 배웠습니다!

배운 내용을 실습에 적용하고 React로 첫 번째 미니 앱을 만들기 위해 Tutorial을 참고해 보세요.

Reference

profile
job's done

0개의 댓글