공부하기/React

Create React App 실행해보기 - 2주차

hyunjicraft 2022. 6. 15. 23:46

크롬 브라우저에서 React Developer Tools 확장 프로그램 설치하기

 

https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

 

 

React Developer Tools

Adds React debugging tools to the Chrome Developer Tools. Created from revision 7f673317f on 5/31/2022.

chrome.google.com

 

확장 프로그램으로 설치된 Components 탭을 클릭하면 페이지의 실제 컴포넌트를 보여준다.

Component 탭

클릭하면 각 컴포넌트의 props와 값을 볼 수 있다.

직접 값을 변경할 수도 있다.

 


컴포넌트를 파일로 분리하기

 

Create React App은 기본적으로 App.js 파일에서 App 컴포넌트를 불러오기 때문에 앱에서 처음 보여지는 내용을 변경하려면 App.js 파일을 변경하면 된다.

//index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
...

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
...

 

컴포넌트들을 각각 파일로 분리해서 작성하면 App.js 파일의 내용이 간결해지고, 다른 파일에서도 import만 하면 각각의 컴포넌트들을 사용할 수 있다.

파일로 분리한 컴포넌트들

//Content.js

import { Component } from 'react';

class Content extends Component {
    render() {
        return (
            <article>
                <h1>{this.props.title}</h1>
                {this.props.desc}
            </article>
        );
    }
}

export default Content;


//Subject.js

import { Component } from 'react';

class Subject extends Component {
    render() {
        return (
        <header>
            <h1>{this.props.title}</h1>
            {this.props.sub}
        </header>
        );
    }
}

export default Subject;

//TOC.js

import { Component } from 'react';

class TOC extends Component {
  render() {
    return (
        <nav>
            <ul>
                <li><a href="1.html">HTML</a></li>
                <li><a href="2.html">CSS</a></li>
                <li><a href="3.html">JavaScript</a></li>
            </ul>
        </nav>
    );
  }
}

export default TOC;

 

App.js 파일에 기존에 작성한 컴포넌트를 지우고 파일로 분리된 컴포넌트를 호출만 하도록 변경한다.

//App.js

import './App.css';
import { Component } from 'react';
import TOC from './components/TOC'
import Subject from './components/Subject'
import Content from './components/Content'

class App extends Component {
  render() {
    return (
      <div className='App'>
        <Subject title="WEB" sub="world wide web!"></Subject>
        <TOC></TOC>
        <Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
      </div>
    );
  }
}

export default App;

 

실행 결과 - 컴포넌트를 파일로 분리한 후에도 동일함.


State 사용해보기

App.js 파일에서 Subject라는 컴포넌트를 사용할 때 title과 sub라는 props를 이용하여 컴포넌트의 내용에 약간의 변화를 줄 수 있었다.

기존에는 title과 sub를 하드코딩해서 컴포넌트에 전달했는데 만약 title과 sub라는 props를 외부에서 알 필요가 없다면 State를 이용하면 App.js 파일을 더 명시적으로 작성할 수 있다.

 

실습1 - Subject 컴포넌트 변경

props를 하드코딩한 기존 코드

// App.js

import './App.css';
import { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div className='App'>
        <Subject title="WEB" sub="World Wide Web!"></Subject>
      </div>
    );
  }
}

export default App;

 

생성자에서 state를 이용하여 값을 전달하는 방식으로 변경한 코드.

// App.js

import './App.css';
import { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      subject: {title: "WEB", sub: "World Wide Web!"}
    }
  }
  render() {
    return (
      <div className='App'>
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject>
      </div>
    );
  }
}

export default App;

 

실습2 - TOC 컴포넌트 변경

props를 하드코딩한 기존 코드

// App.js

import './App.css';
import { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div className='App'>
        <TOC></TOC>
      </div>
    );
  }
}

export default App;


// TOC.js

import { Component } from 'react';

class TOC extends Component {
  render() {
    return (
        <nav>
            <ul>
                <li><a href="1.html">HTML</a></li>
                <li><a href="2.html">CSS</a></li>
                <li><a href="3.html">JavaScript</a></li>
            </ul>
        </nav>
    );
  }
}

export default TOC;

 

생성자에서 state를 이용하여 값을 전달하는 방식으로 변경한 코드.

// App.js

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

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      subject: {title: "WEB", sub: "World Wide Web!"},
      contents: [
        {id: 1, title: "HTML", desc: 'HTML is for information'},
        {id: 2, title: "CSS", desc: 'CSS is for design'},
        {id: 3, title: "JavaScript", desc: 'JavaScript is for interactive'}
      ]
    }
  }
  render() {
    return (
      <div className='App'>
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject>
        <TOC data={this.state.contents}></TOC>
      </div>
    );
  }
}

export default App;


// TOC.js

import { Component } from 'react';

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

export default TOC;

* 리스트의 내용을 바꾸고 싶을 때 TOC.js 파일의 로직을 변경하지 않아도 App.js 파일의 contents 값만 변경하면 된다.


이벤트 

 

실습 1 - 이벤트 구현하기

WEB이라는 문자를 클릭하면 alert가 뜨도록 이벤트를 추가한다.

alert

 

리액트로 이벤트를 구현하려면 onClick={} 중괄호 안에 코드를 작성한다.

리액트의 장점 중 하나가 페이지를 새로고침하지 않아도 유연한 앱을 구현할 수 있는 것인데, HTML에서는 a 태그가 기본적으로 페이지를 새로고침하는 특성이 있기 때문에 e.preventDefault() 함수를 추가해준다.

import './App.css';
import { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      subject: {title: "WEB", sub: "World Wide Web!"}
    }
  }
  render() {
    return (
      <div className='App'>
        <header>
            <h1><a href="/" onClick={function (e) {
              alert('Hello');
              e.preventDefault();
            }}>{this.state.subject.title}</a></h1>
            {this.state.subject.sub}
        </header>
      </div>
    );
  }
}

export default App;

 

실습2 - a태그 클릭 시 이벤트 함수로 state 변경하기

 

state = "read" state = "welcome"
// App.js
...

<header>
    <h1><a href="/" onClick={function (e) {
      e.preventDefault();
      this.setState({ mode: "welcome"});
// this.state.mode = "welcome" 으로 직접 값을 변경할 수도 있지만
// 리액트가 값 변경을 인지하고 render함수를 다시 호출하기 위해 setState()를 써준다.
    }.bind(this)}>{this.state.subject.title}</a></h1>
	{/* bind를 통해 App 컴포넌트를 this로 참조할 수 있다. */}
    {this.state.subject.sub}
</header>

...

 

실습3 - 컴포넌트에 이벤트 만들기

 

Subject 컴포넌트는 a태그에 연결된 onChangePage라는 이벤트 props를 가지고 있다.

Subject 컴포넌트를 사용할 때 이 이벤트에 함수를 구현한다.

// Subject.js

import { Component } from 'react';

class Subject extends Component {
    render() {
        return (
        <header>
            <h1><a href="/" onClick={function(e) {
                e.preventDefault();
                this.props.onChangePage();
            }.bind(this)}>{this.props.title}</a></h1>
            {this.props.sub}
        </header>
        );
    }
}

export default Subject;


// App.js

import './App.css';
import { Component } from 'react';
import TOC from './components/TOC'
import Subject from './components/Subject'
import Content from './components/Content'

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mode: 'read',
      subject: {title: "WEB", sub: "World Wide Web!"},
      welcome: {title: 'Welcome', desc: 'Hello, React!'},
      contents: [
        {id: 1, title: "HTML", desc: 'HTML is for information'},
        {id: 2, title: "CSS", desc: 'CSS is for design'},
        {id: 3, title: "JavaScript", desc: 'JavaScript is for interactive'}
      ]
    }
  }
  render() {
    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;
    }
    return (
      <div className='App'>
        <Subject
          title={this.state.subject.title} 
          sub={this.state.subject.sub}
          onChangePage={function () {
            this.setState({ mode: "welcome"});
          }.bind(this)}
        ></Subject>
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}

export default App;