본문 바로가기
React

[React] 주요 개념 정리

by happy coding! 2019. 4. 24.
반응형

React 주요 개념 정리

  • 다음은 리액트 공식 사이트(https://reactjs.org/)의 Docs 를 읽고 요약 정리한 내용입니다.

Hello World

  • 가장 단순한 React 예시

  • 아래 코드는 페이지에 "Hello, world!"라는 제목을 보여준다.

ReactDOM.render( 
    <h1> Hello, world! </h1>,
    document.getElementById('root')  
);

최신 자바스크립트 문법

  • let and const 문을 사용하여 변수를 정의한다.
  • class 키워드를 사용하여 JavaScript 클래스를 정의한다. 객체와 달리 클래스 메소드 사이에 쉼표를 넣을 필요가 없다. 클래스가 있는 다른 많은 언어와 달리 JavaScript에서는 this 메소드의 값이 호출되는 방식에 따라 다르다.
  • 때때로 "화살표 함수" =>를 정의 하기 위해 사용한다.

JSX 소개

  • 아래 변수 선언을 살펴보자.

    const element = <h1> Hello, world! </h1>;
  • 위에 희한한 태그 문법은 문자열도, HTML도 아닌 JSX 라 JavaScript를 확장한 문법이다.

  • React와 함께 사용할 것을 권장함

  • JSX는 React 엘리먼트(element)를 생성한다.

JSX란?

  • React는 별도의 파일에 마크업과 로직을 넣어 기술을 인위적으로 분리하는 대신, 둘 다 포함하는 "컴포넌트"라고 부르는 느슨하게 연결된 유닛으로 관심사를 분리한다.

JSX에 표현식 포함하기

  • 아래 코드에서는 name이라는 변수를 선언한 후 중괄호로 감싸 JSX안에 사용하였다.

    const name = 'spring';
    const element = <h1> Hello, {name} </h1>;
    ReactDOM.render(
    element,
    document.getElementById('root')
    );
  • JSX의 중괄호 안에는 유효한 모든 JavaScript 표현식을 넣을 수 있다. 예를 들어 2 + 2, user.firstName 또는 formatName(user) 등은 모두 유효한 JavaScript 표현식이다.

JSX도 표현식이다

  • JSX를 if 구문 및 for loop 안에 사용하고, 변수에 할당하고, 인자로서 받아들이고, 함수로부터 반환할 수 있다.

JSX 속성 정의

  • 속성에 따옴표를 이용해 문자열 리터럴을 정의할 수 있다.

    const element = <div tabIndex = "0"></div>
  • 중괄호를 사용하여 어트리뷰트에 JavaScript 표현식을 삽입할 수도 있음

    const element = <img src = {user.avatarUrl}</img>;
  • JSX는 HTML 보다는 Javascript에 가깝기 때문에 camelCase 프로퍼티 명명 규칙을 사용한다.

  • 태그가 비어있다면 XML처럼 />를 이용해 바로 닫아주어야 한다.

  • JSX 태그는 자식을 포함할 수 있다.

  • JSX는 주입 공격을 방지한다.

  • JSX는 객체를 표현한다.

React 엘리먼트

  • Babel 은 JSX를 react.createElement() 호출로 컴파일한다.

  • React.createElement()는 버그가 없는 코드를 작성하는데 도움이 되도록 몇 가지 검사를 수행하며, 기본적으로 아래와 같은 객체를 생성한다.

    const element = {
    type: 'h1',
    props: {
      className: 'greeting',
      children: 'Hello, world!'
    }
    };
  • 이러한 객체를 "React 엘리먼트"라고 하며, 이를 화면에 표시하려는 항목에 대한 설명이라고 생각할 수 있다.

엘리먼트 렌더링

  • 엘리먼트는 React 앱의 가장 작은 단위

  • 엘리먼트는 화면에 표시할 내용을 기술한다.

    const element = <h1>Hello, world </h1>;
  • 브라우저 DOM 엘리먼트와 달리 React 엘리먼트는 일반 객체(plain object)이며 쉽게 생성할 수 있다.

  • React DOM은 React 엘리먼트와 일치하도록 DOM을 업데이트한다.

DOM에 엘리먼트 렌더링하기

  <div id = "root"> </div>
  • 이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하기 때문에 이것을 루트(root) DOM 노드라고 부른다.
  • React로 구현된 애플리케이션은 일반적으로 하나의 루트 DOM 노드가 있다.
  • React 엘리먼트를 루트 DOM 노드에 렌더링하려면 둘 다 ReactDOM.render()로 전달하면 된다.

렌더링된 엘리먼트 업데이트하기

  • React 엘리먼트는 불변객체이다. 엘리먼트를 생성한 이후에는 해당 엘리먼트의 자식이나 속성을 변경할 수 없다.
  • React DOM은 해당 엘리먼트와 그 자식 엘리먼트를 이전의 엘리먼트와 비교하고 DOM을 원하는 상태로 만드는데 필요한 경우에만 DOM을 업데이트한다.

함수 컴포넌트와 클래스 컴포넌트

  • 컴포넌트를 통해 UI를 재사용 가능한 개별적인 여러 조각으로 나누고, 각 조각을 개별적으로 살펴볼 수 있다.
  • 개념적으로 컴포넌트는 javascript 함수와 유사하다.
  • "props"라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다.
  • 컴포넌트를 정의하는 가장 간단한 방법은 javascript 함수를 작성하는 것이다.
function welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
  • 이 함수는 데이터를 가진 하나의 "props(props는 속성을 나타내는 데이터)" 객체 인자를 받은 후 React 엘리먼트를 반환하므로 유효한 컴포넌트이다. 이러한 컴포넌트는 javascript 함수이기 때문에 말그대로 "함수 컴포넌트"라고 부른다.

  • 또한 ES6 class를 사용하여 컴포넌트를 정의할 수 있다.

    class Welcom extends React.component {
    render() {
      return <h1>Hello,  {this.props.name}</h1>;
    }
    }
  • React의 관점에서 볼 때 위 두 가지 유형의 컴포넌트는 동일하다.

컴포넌트 렌더링

  • React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 JSX 어트리뷰트를 해당 컴포넌트에 단일 객체로 전달한다. 이 객체를 "props"라고 한다.
  • 컴포넌트의 이름은 항상 대문자로 시작한다.

컴포넌트 합성

  • 컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있다.
  • React 앱에서는 버튼, 폼, 다이얼로그, 화면 등의 모든 것들이 흔히 컴포넌트로 표현된다.
  • 일반적으로 새 React 앱은 최상위에 단일 App 컴포넌트를 가지고 있다.
  • 기존 앱에 React를 통합하는 경우에는 Button 과 같은 작은 컴포넌트부터 시작해서 뷰 계층의 상단으로 올라가면서 점진적으로 작업해야 한다.

컴포넌트 추출

  • 컴포넌트를 여러 개의 작은 컴포넌트로 나누기
function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}
  • 이 컴포넌트는 author(객체), text(문자열) 및 date(날짜)를 props로 받은 후 소셜 미디어 웹 사이트의 코멘트를 나타낸다.

  • 이 컴포넌트는 구성요소들이 모두 중첩 구조로 이루어져 있어서 변경하기 어렵고, 각 구성 요소를 개별적으로 재사용하기도 힘들다.

  • Avatar 추출하기

    function Avatar(props) {
    return (
      <img className="Avatar"
        src={props.user.avatarUrl}
        alt={props.user.name}
       />
    );
    }
  • 다음은 Avatar 옆에 사용자의 이름을 렌더링하는 UserInfo 컴포넌트를 추출한다.

    function UserInfo(props) {
    return (
      <div className="UserInfo">
        <Avatar user={props.user} />
        <div className="UserInfo-name">
          {props.user.name}
        </div>
    );
    }
  • 기존의 Comment가 더욱 단순해졌다.

    function Comment(props) {
    return (
      <div className="Comment">
        <UserInfo user={props.author} />
        <div className="Comment-text">
          {props.text}
        </div>
        <div className="Comment-date">
          {formatDate(props.date)}
        </div>
       </div>
    );        
    }
  • 컴포넌트를 추출하는 작업이 지루할 수 있다.

  • 하지만 재사용 가능한 컴포넌트를 만드는 것은 더 큰 앱에서 작업할 때 두각을 나타낸다.

  • UI 일부가 여러번 사용되거나 (Button, Panel, Avatar), UI 일부가 자체적으로 복잡한 (App, FeedStory, Comment) 경우에는 재사용 가능한 컴포넌트를 만드는 것이 좋다.

props는 읽기 전용이다

  • 함수 컴포넌트나 클래스 컴포넌트 모두 컴포넌트의 자체 props를 수정해서는 안된다.

  • 순수 함수 : 입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하는 함수

    function sum(a, b) {
      return a + b;
    }
  • 아래 함수는 자신의 입력값을 변경하기 때문에 순수 함수가 아니다.

    function withdraw(account, amount) {
      account.total -= amount;
    }
  • React는 매우 유연하지만 한 가지 엄격한 규칙이 있다.

  • 모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 순수 함수처럼 동작해야 한다.

  • 애플리케이션 UI는 동적이며 시간에 따라 변한다. React 컴포넌트는 state를 통해 위 규칙을 위반하지 않고 사용자 액션, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력값을 변경할 수 있다.

State 및 Lifecycle

function tick() {
  const element = (
    <div>
      <h1> Hello, world! </h1>
      <h2> It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);
  • Clock 구성 요소를 실제로 재사용하고 캡슐화하기
  • 자체 타이머를 설정하고 매 초마다 업데이트한다.
  • 시계를 캡슐화한다.
function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

함수를 클래스로 변환

  • 시계와 같은 기능 구성요소를 다음 다섯 단계로 클래스로 변환할 수 있다.
  1. 리액트를 확장하는 동일한 이름을 가진 ES6 클래스를 만든다.
  2. render()라는 단일 빈 메소드를 추가한다.
  3. 함수의 본문을 render() 메서드로 이동시킨다.
  4. render() body에서 props를 this.props로 교체한다.
  5. 나머지 빈 함수 선언은 삭제한다.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • Clock은 이제 함수보다는 클래스로 정의된다.

클래스에 Local State 추가

  • date를 3단계에 걸쳐 props에서 state로 변경하기
  1. render() method에서 this.props.date를 this.state.date로 교체한다.

    class Clock extends React.Component {
     render() {
         return (
             <div>
                 <h1>Hello, world! </h1>
                 <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
             </div>
         );
     }
    }
  2. this.state를 초기화하는 클래스 생성자를 추가한다.

    class Clock extends React.Component {
    constructor(props) {
     super(props);
     this.state = {date: new Date()};
    }
    
    render() {
     return (
       <div>
         <h1>Hello, world!</h1>
         <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
       </div>
     );
    }
    }
  3. 엘리먼트로부터 date prop을 제거한다.

    ReactDOM>render(
     <Clock />,
     document.getElementById('root')
    );
  • 결과 코드는 다음과 같다.
    class Clock extends React.Component {
    constructor(props) {
      super(props);
      this.state = {date: new Date()};
    }

    render() {
      return (
        <div>
          <h1> Hello, world!</h1>
          <h2> It is {this.state.date.toLocaleTimeString()}.</h2>
        </div>
      );
    }
    }

ReactDOM.render(  
    <Clock />,
    document.getElementById('root')  
);  

클래스에 라이프 사이클 메소드 추가

  • Clock 이 처음으로 DOM에 렌더링될 때마다 타이머를 설정하기를 원한다. 이것을 리액트에서는 마운팅이라고 한다.
  • Clock에
반응형

댓글