Web Programming/React

React의 시작

안녕하세요?

씨앤텍시스템즈입니다.

 

이번 포스트에서는 React로 간단한 애플리케이션을 생성해보려고 합니다. 

React의 시작

React는 Single Page Application으로 각각의 페이지가 명확하게 나뉘어져 있는 특징을 가지고 있습니다.

 

첫 애플리케이션이라고 불리는 것이 구글의 Gmail인데요, Gmail을 보면 '웹 사이트' 보다는 '애플리케이션'이라는 느낌을 받습니다.

웹 애플리케이션은 데이터가 정말 많은데, 데이터를 바꾸면 화면도 함께 바뀌어야 합니다. 이러한 동적인 기능을 웹 사이트로 구현하기에는 굉장한 어려움이 있습니다.

그 문제를 해결하기 위해 Single Page Application 프로그램이 나오기 시작하였습니다.

 

페이스북은 React를 만들었습니다. 이로써 데이터와 화면의 불일치를 해결하였습니다. 

일반적인 문서 페이지에는 React를 사용할 필요가 없습니다. 즉, 모든 사이트를 Single Page Application으로 만들필요는 없습니다. 

 

장점과 단점 

React로 만들어진 웹 애플리케이션에는 페이지의 깜박거림 없이 자연스러움 페이지 전환이 가능합니다.

하지만, 네이버나 다음에서는 React로 만든 페이지가 검색 엔진에 노출이 잘 안 된다고 합니다.

 

React는 데이터를 중심으로 움직입니다. 사용자 정의 태그를 만들어주는 여러가지 기술이 있는데 React 역시 그러한 기술 중에 하나입니다. 사용자 정의 태그를 React에서는 component라고 합니다. 이러한 사용자 정의 태그를 재사용할 수 있다는 것 또한 React의 큰 장점입니다. 이로 인해 실시간으로 유지보수를 할 수 있고, 변경된 사항은 전체에 적용이 됩니다. 

 

create-react-app

npm

npm version을 확인하여 npm의 설치 여부를 먼저 확인 합니다.

(npm 설치 시에 권한 에러가 뜨면 명령어 앞에 sudo를 붙여서 실행합니다)

 

참고로, npm이 프로그램을 설치하는 프로그램이라면, npx는 예를 들어, React라는 프로그램을 임시로 설치해서 한 번만 실행가능하도록 만드는 것으로, 실행하고 나면 지워집니다. npx의 장점은 설치할 때마다 최신 버전을 받을 수 있다는 것입니다.

create-react-app 설치

1. npm 또는 npx를 통한 create-react-app 설치

2. version을 통한 설치 여부 확인

3. cd 명령어를 통한 작업 폴더 지정

4. 'create-react-app .'을 통해 해당 디렉터리에 create-react-app 설치

    ('   .'은 현재 디렉터리를 의미합니다.)

5. npm run start를 실행시키면, 자동으로 웹 브라우저가 열리면서 아래와 같은 최소한으로 구현된 앱 화면을 확인 할 수 있습니다.

위 사진의 Local과 On Your Network는 개발 중인 앱을 확인하는 주소입니다.

 

component

컴포넌트는 반드시 하나의 최상위 컴포넌트에서 시작해야 합니다.

여기서 App.js를 최상위 컴포넌트로 설정하도록 합니다. app 폴더에 components라는 하위 폴더를 생성하여 각 기능을 담당하는 하위 컴포넌트를 생성하여 줍니다. 예를 들어 subject 컴포넌트를 생성하여 App.js에서 import 합니다.

import React, {Component} from 'react';
import Subject from './components/Subject';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Subject></Subject>
      </div>
    )
  }
  
}
export default App;

 

 

import React, {Component} from 'react';

class Subject extends Component {
    render(){
        console.log('Subject rendered')
      return (
       <header>
        <h1>WEB</h1>
        World wide web!
      </header>
      );
    }
  }

  export default Subject;

class Subject extends Component {} 는 Subject라는 컴포넌트를 만들겠다는 의미로, 반드시 render()라는 함수를 가지고 있어야 합니다.

이렇게 작성되는 코드는 유사 JS입니다. 즉, JS가 아닙니다. 이러한 문법을 따르는게 까다롭기 때문에 페이스북에서 만든 것이 JSX입니다. 위와 같이 JSX 코드를 작성하면 create-react-app이 알아서 JS 코드로 변환해주는 것입니다.

 

(+) React Developer Tools

크롬에서 위의 확장 프로그램을 설치하면, 아래 사진과 같이 개발자 도구를 통해 React에서 작성된 component를 중심으로 코드를 볼 수 있습니다. 

state

상위 component인 App의 상태를 하위 component로 전달하기 위해서 상위 component의 state를 하위 component의 props 값으로 넣습니다.

컴포넌트 생성자 안에는 초기화 함수인 constructor() 가 존재합니다. 이러한 constructor는 컴포넌트가 실행될 때, render () 함수보다 먼저 실행되면서 그 component를 초기화 시켜주려고 하는 코드는 constructor 안에 코드를 작성합니다.

 

App의 내부 state를 TOC에 주입하는 것을 통해 자동으로 데이터가 바뀌도록 해볼 것이다.

먼저 위의 목표를 위해 아래와 같이 작성해봅니다.

class TOC extends Component {
    render() {
        var lists = [];
        var data = this.props.data;
        var i = 0;
        while(i < data.length) {
            lists.push(<li>
                <a href={"/contents/"+data[i].id}>{data[i].title}</a>
            </li>)
            i = i+ 1;
        }
      return (
        <nav>
          <ul>
              {lists}
          </ul>
      </nav>
      );
    }
  }

이처럼 element 여러 개를 자동으로 생성할 경우,

위와 같이, 각각의 lists 항목들은 key라고 하는 prop을 가지고 있어야 한다는 에러가 뜬다.

이 에러를 해결하기 위해 

 lists.push(<li key={data[i].id}>
                <a href={"/contents/"+data[i].id}>{data[i].title}</a>
            </li>)

이러한 식별자를 입력하게 되는데, 이것은 React가 내부적으로 필요해서 요청하는 데이터이다.

먼저, 우리가 보는 페이지가 welcome 페이지 인지 보여주기 위해서,  state에 welcome이라는 객체를 추가한다. 

 

React에서는 state 혹은 props의 값이 바뀌면 state를 가지고 있는 component에 render함수가 다시 호출된다. 그리고 render 함수 하위에 있는 각각의 component의 render 함수도 다시 호출된다. 즉, 화면이 다시 그려지는 것이다.

 return (
      <div className="App">
        <header>
            <h1>
            <a href="/" onClick={function(e) {
              console.log(e);
              e.preventDefault();
              ✔ this.state.mode = 'welcome'
            }}>{this.state.subject.title}</a>
            </h1>
            {this.state.subject.sub}
      </header>
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
    )

하지만, 변경하기 위한 값을 일반적인 JS와 같이(✔)  속성 값을 변경하면 에러를 확인할 수 있습니다.

첫 번째 원인은 react 문법으로 속성을 변경해야 한다는 점과 두 번째는 this 값을 찾지 못한다는 점입니다. 

첫 번째 원인은 setState() 메서드를 이용하여 속성을 변경시키고, 두 번째 원인은 해당 setState() 메서드가 끝난 직후에 실행되도록 bind(this)를 호출하여 해결합니다.

정리하자면 아래와 같은 코드로 작성합니다.

 return (
      <div className="App">
        <header>
            <h1>
            <a href="/" onClick={function(e) {
              console.log(e);
              e.preventDefault();
              ✔ this.setState({
                mode: 'welcome'
              })
            }.bind(this)}>{this.state.subject.title}</a>
            </h1>
            {this.state.subject.sub}
      </header>
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
    )

 

(그렇다면 this는 무엇일까요?)

this를 console로 찍어보면 아래와 같이 component 본인을 나타냄을 알 수 있습니다.

 

props

위에서 state를 setState()로 수정할 수 있었던 것과 달리 props는 read only입니다.  예를 들어,

render() {
    console.log('App rendered')
    var _title, _desc = null;

    if(this.state.mode === 'welcome') {
      _title = this.state.welcome.title;
      _desc = this.state.welcome.desc;
    } 
    else if (this.state.mode === 'read') {
      _title = this.state.contents[0].title;
      _desc = this.state.contents[0].desc;
}

위와 같이 변수를 지정하고,

<Content title={_title} desc={_desc}></Content>

Content라고 하는 component를 사용하는 쪽에서는 title이라고하는 props를 통해 값을 주입할 수 있습니다.

Component 안에서 자기 자신으로 전달된 prorps 값을 바꾸는 것은 금지되어 있기 때문에 Content 내부에서 전달된 title의 값을 바꾸기 위해서는 evnet 인 setState() 를 사용해서 변경할 수 있습니다.

 

이러한 state와 props를 적절히 사용하여 UI를 변경할 수 있습니다.

 

지금까지 React의 시작에 대해서 알아보았습니다.

 

참고자료

https://opentutorials.org/course/4900

728x90