✍ 리액트 공식 사이트 http://react.dev 에서 배우게 될 내용

  • components(컴포넌트) 생성과 중첩
  • 마크업 및 스타일 추가 방법
  • 데이터를 표시하는 방법
  • conditions(조건) 및 목록(lists) 렌더링 하는 방법
  • 이벤트 응답과 화면 업데이트 방법
  • 컴포넌트 간에 데이터를 공유하는 방법

📚 Creating and nesting components : 컴포넌트 생성과 중첩

 리액트 앱들은 컴포넌트들로 구성된다. 컴포넌트는 고유의 로직과 외관을 갖는 UI(사용자 인터페이스)의 일부이다.

컴포넌트는 버튼만큼 작을 수도 있고, 전체 페이지만큼 클 수도 있다.

 

리액트 컴포넌트는 마크업을 반환하는 자바스크립트 함수이다:

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

위 코드는 함수형 컴포넌트로 return안에 마크업 언어인 <button>태그를 MyButton 이라는 컴포넌트로 선언하였다.

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

 

컴포넌트를 만들 때는 대문자로 시작한다는 점을 주의한다. 그래야 해당요소가 리액트 컴포넌트라는 것을 알 수 있다.

리액트 컴포넌트는 첫글자를 대문자로, HTML태그는 소문자로 작성한다.

 

해당 요소들을 App.js에 작성해서 결과를 알아보도록 한다.

// App.js

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

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

 


실행 결과

Welcome to my app


export default 키워드는 파일의 메인 컴포넌트를 지정한다. 만약 자바스크립트 구문이 익숙하지 않다면, MDNjavascript.info 에서 참고자료를 확인한다.

 

📚 Writing markup with JSX : JSX로 마크업 쓰기

위에서 보신 마크업 구문은 JSX라고 한다. 선택 사항이지만 대부분의 리액트 프로젝트는 JSX를 사용한다. 로컬 개발에 권장하는 모든 도구는 JSX를 즉시 지원한다.

 

JSX는 HTML보다 더 엄격하다. <br />와 같은 단일 태그는 반드시 닫는 태그를 표시해줘야 한다. 또한 컴포넌트는 여러 개의 JSX 태그를 return할 수도 없다. 공유된 상위 태그를 <div>.../div> 또는 빈 태그 <>...</> 와 같이 묶어야 한다 :

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

JSX로 포팅할 HTML이 많다면 온라인 컨버터를 사용할 수 있다.

온라인 컨버터 사용 예시

 

📚 Adding styles : 스타일 추가하기

React에서 className으로 CSS의 class를 지정한다. HTML의 class속성과 동일하게 작동한다

<img className="avatar" />

 

리액트에서 className으로 선언한 요소에 스타일을 CSS파일에서 선언해보도록 하겠다.

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

 

리액트는 CSS 파일을 추가하는 방법을 규정하지 않는다. 가장 간단한 경우에는 HTML에 <link> 태그를 추가할 것이다. 빌드 도구나 프레임워크를 사용하는 경우, CSS 파일을 프로젝트에 추가하는 방법은 해당 문서를 참조하면 된다.

( 리액트 프로젝트의 App.css에 작성하거나 index.html에서 선언해주면 될거 같다.)

 

📚 Displaying data : 데이터 표시

JSX는 마크업을 JavaScript에 넣을 수 있게 해준다. { 중괄호 }를 사용하면 코드에서 변수를 추출하여 사용자에게 표시할 수 있다. 다음 user.name을 예로 들어보자 :

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

 

JSX 속성에서도 중괄호{ }를 사용하여 JavaScript로 "이스케이프(escape)"할 수 있지만 따옴표 대신 중괄호를 사용해야 한다. 예를 들어, className="avatar"는 "avatar" 문자열을 CSS 클래스로 전달하지만, src={user.imageUrl}는 JavaScript에서 user.imageUrl 변수 값을 읽어와 해당 값을 src 속성으로 전달한다.

return (
  <img
    className="avatar"
    src={user.imageUrl}
  />
);

 

JSX 중괄호 내에는 더 복잡한 표현식도 넣을 수 있다. 예를 들면, 문자열 연결을 할 수 있다:

// App.js

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

 


실행 결과

Hedy Lamarr

Photo of Hedy Lamarr

위 예제에서, style={ { } }는 특별한 문법이 아니라, style={ } JSX 중괄호 내의 일반적인 { } 객체다. style 속성은 스타일이 JavaScript 변수에 의존할 때 사용할 수 있다.

 

📚 Conditional rendering : 조건부 렌더링

React에서는 조건을 작성하는 데 특별한 문법이 없다. 대신, 일반적인 JavaScript 코드를 작성할 때 사용하는 기술을 그대로 사용한다. 예를 들어, JSX를 조건에 따라 조건적으로 포함시키기 위해 if 문을 사용할 수 있다:

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

 

코드를 더 간결하게 작성하려면 삼항 연산자(conditional ? operator)를 사용할 수 있다. if 문과 달리 이 연산자는 JSX 내부에서도 작동한다:

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

 

else 가 필요하지 않은 경우, 더 간결한 논리 && 구문을 사용할 수도 있다:

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

 

이러한 모든 접근 방식은 속성을 조건적으로 지정하는 데도 동일하게 작동한다. JavaScript 구문 중 일부가 익숙하지 않다면 항상 if...else를 사용하여 시작할 수 있다.

📚 Rendering lists : 목록 렌더링

리스트 형태의 컴포넌트를 렌더링하기 위해 for 루프와 배열의 map() 함수와 같은 JavaScript 기능을 활용할 것이다.

예를 들어, 제품 목록 배열이 있다고 가정해보겠다:

 

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

 

컴포넌트 내에서 map() 함수를 사용하여 제품 배열을 <li> 아이템의 배열로 변환하는 예:

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

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

 

<li>에는 key 속성이 있는 것을 주목한다. 리스트의 각 항목에 대해 해당 항목을 형제들 중에서 고유하게 식별하는 문자열 또는 숫자를 전달해야 한다. 일반적으로 키는 데이터에서 가져와야 한다. 예를 들어 데이터베이스 ID와 같은 값이 될 수 있다. React는 키를 사용하여 나중에 항목을 삽입, 삭제 또는 재정렬할 때 무엇이 발생했는지를 알게 된다.

 

// App.js

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

실행 결과

  • Cabbage
  • Garlic
  • Apple

📚 Responding to events : 이벤트 응답하기

이벤트에 응답하려면 컴포넌트 내에서 이벤트 핸들러 함수를 선언할 수 있다:

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

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

 

onClick={handleClick}에서 괄호가 없음에 주목한다! 이벤트 핸들러 함수를 직접 호출하지 않고 함수를 전달만 하면 된다. 사용자가 버튼을 클릭할 때 React가 이벤트 핸들러를 호출한다.

 

📚 Updating the screen : 화면 업데이트

종종 컴포넌트가 특정 정보를 "기억"하고 표시하게 하고 싶을 때가 있다. 예를 들어, 버튼이 클릭된 횟수를 세고 싶을 수 있다. 이를 위해 컴포넌트에 상태를 추가하도록 한다.

 

우선, 'react' 라이브러리로 부터 useState를 추가하도록 한다.

import { useState } from 'react';

 

이제 아래와 같이 컴포넌트 내에서 상태 변수를 선언할 수 있다:

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

 

`useState`를 통해 두 가지를 얻게 된다: 현재 상태(`count`)와 상태를 업데이트하는 함수(`setCount`)다. 어떤 이름으로도 지정할 수 있지만, 일반적으로 `[something, setSomething]` 형태로 작성하는 것이 관례다.

버튼이 처음 표시될 때 `count`는 0이 된다. 왜냐하면 `useState(0)`에 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>
  );
}

실행 결과


각 버튼이 자체적으로 상태를 "기억"하고 다른 버튼에 영향을 미치지 않는 것을 주목한다.

+ Recent posts