Develop/React Native

[React/Inflearn] 생활코딩 React

안다희 2019. 6. 22. 03:19
728x90

React : Facebook에서 만든 Javascript UI Library

 

Component : 사용자 정의 태그 

1. 가독성

2. 재사용성

3. 유지보수

 

 

https://reactjs.org/docs/create-a-new-react-app.html#create-react-app

 

Create a New React App – React

A JavaScript library for building user interfaces

reactjs.org

클릭!

> npm install -g create-react-app@2.1.8

-g : 터미널 어디에서나 사용 가능!

맥 : sudo 추가

 

C:\Users\user\Desktop\dev\expo\myNewProject>create-react-app
Please specify the project directory:
  create-react-app <project-directory>

For example:
  create-react-app my-react-app

Run create-react-app --help to see all options.

이렇게 뜨면 성공!

 

C:\Users\user\Desktop\react-app>create-react-app .

Creating a new React app in C:\Users\user\Desktop\react-app.

Quick Overview 의 npx는 항상 최신버전을 해주기 때문에 실무에서 추천!

 

 

아무든 create-react-app 해주고 vscode 켜고 그 위치에서 

npm start 해주면 웹브라우저 뜸!

 

7/40 부터

https://www.inflearn.com/course/react-%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9/lecture/20305

불러오는 중입니다...

App.js를 다음과 같이 class type으로 변경!

import React, { Component} from 'react';
// import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">

      </div>
    );
  }
}

export default App;

 

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Apfdp from './App';  ///!!!!!!!!!!!!!!여기랑 
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<Apfdp />, document.getElementById('root'));  ///!!!!!!!!!!!!!!여기랑 

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

// ///!!!!!!!!!!!!!!여기랑  이름만 같으면 됨,, 대신 ./App 이건 파일이름이라 바꾸면 안되겠지

 

새로고침 우클릭 -> 캐시 비우기 및~~~ 그거 용량 엄청 커 배포할 땐 이러면 ㅇ안되겠지

npm run start

 

빌드할 때는 npm run build (배포 느낌)

그러면 build폴더생김

create react app이 불필요한 용량 다 없앰.

 

실제로 배포할 땐 build에 있는 파일들을 하면됨

 

npm install -g serve : npm을 통해 설치할 수 있는 웹 서버

serve 명령어 통해 웹서버 설치 가능

npx serve -s build : build 폴더를 배포하겠다!?

 

npx serve -s build하고 다시 개발자도구 켜서 로컬 웹페이지에서 용량 확인해보면

용량이 줄어들었다!

이전에는 1.7MB였었는디

 

 

====대망의 component====

10/40

 

https://reactjs.org/docs/components-and-props.html

 

Components and Props – React

A JavaScript library for building user interfaces

reactjs.org

 

만든 컴포넌트에 각각 다른 속성을 적용하고 싶을 때! 다 문서에 있음여

class Subject extends Component {
  // class 안에 있는 함수는 function 생략
  render() { // 필수 함수
    return ( // 컴포넌트는 하나의 최상위 태그만 쓴다
      <header>
          <h1> {this.props.title} </h1>
          {this.props.sub}
      </header>
    );
  }
}

// 유사 자바스크립트
// JSX : "" 이런거 안따지고 쓸 수 있도록 Facebook에서 만든 유사 자바스크립트!
class App extends Component {
  render() {
    return (
      <div className="App">
        <Subject title="WEB" sub="sub~!"></Subject>
        <Subject title="WEB2" sub="sub~!2"></Subject>
        <TableOfContent />
        <Content />
      </div>
    );
  }
}

이것이 바로 리팩토링!

React에서는 title, sub 같은 것을 props라고 한다.

 

나 이제 React 할 수 있어!

 

14/40

1. 설명서 볼 줄 알기!

2. 여러 가지 가설을 통해 1에서 알아낼 수 없는 부분을 터득하기! state!

3. 질문

4. 검색 

 

 

state!!!

https://reactjs.org/community/support.html

 

Where To Get Support – React

A JavaScript library for building user interfaces

reactjs.org

Community - Tools - Debuging

React로 만들어진 앱의 상태 볼 수 있다.

 

React Developer Tools 확장 프로그램 설치!

 

그러면 개발자도구 Element에서 맨 끝에 React 보면 React상의 코드로 볼 수가 있다!!! 오마이!!

옆에서 바꿀 수도 있따 props 값을

componet 분리!

src 아래 components 폴더 만든다

 

 

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

// 유사 자바스크립트
// JSX : "" 이런거 안따지고 쓸 수 있도록 Facebook에서 만든 유사 자바스크립트!
class App extends Component {
  render() {
    return (
      <div className="App">
        <Subject title="WEB" sub="sub~!"></Subject>
        <Subject title="WEB2" sub="sub~!2"></Subject>
        <TableOfContent />
        <Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
      </div>
    );
  }
}

export default App;

이런식으로 사용!

 

각각의 Table~ Co~ Su~ 이파일들은

각각 이렇게 생겼음

import React, { Component} from 'react';
// 없어도 되면 되는거고 있어야하면 있어야해


class TableOfContent 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 TableOfContent; // 이제 다른 곳에서 사용 가능@

오케이~~

 

 

=====state=====

state는 props라는 개념과 같이 봐야 한다.

props는 사용자가 컴포넌트 사용할 때 중요

state는 props값에 따라 내부 구현값 달라지는?? 그런게 중요

 

props는 사용자에게 중요한 정보

사용자가 알 필요 없는 component 내부적으로 사용되는 것 : state

Props와 State는 철저히 분리되어 있어야 한다.

 

 

TableOfContent.js

import React, { Component} from 'react';
// 없어도 되면 되는거고 있어야하면 있어야해


class TableOfContent extends Component {
  render() {
    var lists = [];
    var data = this.props.data;
    var i = 0;

    while (i < data.length) {
        // key는 react가 필요해서 요청하는 것. 그냥 필요한거래
        lists.push(<li key={data[i].id}><a href={"/content/" + data[i].id}>{data[i].title}</a></li>);
        i = i + 1;
    }
    return (
      <nav>
        <ul>
          {lists}
        </ul>
      </nav>
    );
    
  }
}

// 어떤 것을 외부에서 사용할 수 있도록 할 것인가?
export default TableOfContent; // 이제 다른 곳에서 사용 가능@

 

App.js

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

// 유사 자바스크립트
// JSX : "" 이런거 안따지고 쓸 수 있도록 Facebook에서 만든 유사 자바스크립트!
class App extends Component {
  constructor(props) { // state 값 초기화 그리고 세팅
    super(props); // render보다 먼저 실행되는 함수
    this.state = {
      subject: {title: 'WEB from state', sub: 'World Wisssde Web!'},
      contents: [
        {id: 1, title: 'HTML', desc: 'HTML is HyperText ...'},
        {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>
        <TableOfContent data={this.state.contents} />
        <Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
      </div>
    );
  }
}

export default App;

 

state 어떻게 쓰는지 반복문 어떻게 쓰는지!

 

 

 

[event]

App.js

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

// 유사 자바스크립트
// JSX : "" 이런거 안따지고 쓸 수 있도록 Facebook에서 만든 유사 자바스크립트!
class App extends Component {
  constructor(props) { // state 값 초기화 그리고 세팅
    super(props); // render보다 먼저 실행되는 함수
    this.state = {
      mode: 'welcome',
      subject: {title: 'WEB', sub: 'This is Subject!'},
      welcome: {title: 'Welcome', desc: 'World Wide Web!'},
      contents: [
        {id: 1, title: 'HTML', desc: 'HTML is HyperText ...'},
        {id: 2, title: 'CSS', desc: 'CSS is for design'},
        {id: 3, title: 'JavaScript', desc: 'JavaScript is for interactive'}
      ]
    }
  }

  // props나 state가 바뀌면 해당 render함수가 다시 호출된다. 화면이 다시 그려진다.
  render() {
    console.log('App 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}>
        </Subject> */}
        <header>
          <h1> <a href="/" onClick={function(e) {
            console.log(e);
            e.preventDefault(); // a 태그의 기본적인 동작을 금지한다. like reload
            // 첫번째 파라미터 : event  
            alert('hi'); // reload됨
          }}>{this.state.subject.title}</a> </h1>
          {this.state.subject.sub}
        </header> 
        <TableOfContent data={this.state.contents} />
        <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}

export default App;

e.prevent를 주목!

지금 우리는 a 태그를 클릭하면 App component의 mode를 welcome으로 바꿀거야를 할건데 reload를 막기위해 저 함수를 쓴 것!

 

 

          <h1> <a href="/" onClick={function(e) {
            // 첫번째 파라미터 : event  
            // alert('hi'); // reload됨

            console.log(e);
            e.preventDefault(); // a 태그의 기본적인 동작을 금지한다. like reload
            
            this.state.mode = 'welcome';
            // this의 값이 자기자신 component를 가리키는 것이 x rid 아무것도 없음
            
          }.bind(this)}>{this.state.subject.title}</a> </h1>

this가 자기자신 가리키려면 .bind(this)라고 해야돼.

근데 이렇게 해도 안돼.

 

          <h1> <a href="/" onClick={function(e) {
            // 첫번째 파라미터 : event  
            // alert('hi'); // reload됨

            console.log(e);
            e.preventDefault(); // a 태그의 기본적인 동작을 금지한다. like reload
            
            //this.state.mode = 'welcome';
            // this의 값이 자기자신 component를 가리키는 것이 x rid 아무것도 없음
            this.setState({
              mode: 'welcome'
            });
          }.bind(this)}>{this.state.subject.title}</a> </h1>

이렇게 setState로 해줘야 state가 바뀜!

그럼 이제 a 태그 누르면 mode state가 바뀌어서 _title이랑 _desc가 바뀌겠지

 

 

[bind]

class App extends Component {
  constructor(props) { // state 값 초기화 그리고 세팅
    super(props); // render보다 먼저 실행되는 함수
    this.state = {
      mode: 'read',
      subject: {title: 'WEB', sub: 'This is Subject!'},
      welcome: {title: 'Welcome', desc: 'World Wide Web!'},
      contents: [
        {id: 1, title: 'HTML', desc: 'HTML is HyperText ...'},
        {id: 2, title: 'CSS', desc: 'CSS is for design'},
        {id: 3, title: 'JavaScript', desc: 'JavaScript is for interactive'}
      ]
    }
  }

  // props나 state가 바뀌면 해당 render함수가 다시 호출된다. 화면이 다시 그려진다.
  render() {
    console.log('App 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;
      
    }

    console.log('render', this); // render 안에서 this는 App 컴포넌트 전체를 가리킨다

    return ( // 자바스크립트의 코드로서 실행되게 하고 싶으면 {} 아니면 문자열인 ""
      <div className="App">
        {/* <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}>
        </Subject> */}
        <header>
          <h1> <a href="/" onClick={function(e) {
            // 첫번째 파라미터 : event  
            // alert('hi'); // reload됨

            console.log('event in', this);
            e.preventDefault();
            return;

            console.log(e);
            e.preventDefault(); // a 태그의 기본적인 동작을 금지한다. like reload
            
            this.state.mode = 'welcome';
            // this의 값이 자기자신 component를 가리키는 것이 x rid 아무것도 없음
            this.setState({
              mode: 'welcome'
            });
          }}>{this.state.subject.title}</a> </h1>
          {this.state.subject.sub}
        </header> 
        <TableOfContent data={this.state.contents} />
        <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}

export default App;

render() 아래 this는 App 컴포넌트 전체를 가리키는데

header 안에서 return 위에 로그를 찍어보면 event in 은 undefined다.

그래서 .bind(this)를 위에서처럼 해줘야 강제로 this에 컴포넌트를 주입시킬 수 있다.

 

이런 느낌

이해 안가면 그냥 이렇게 쓰면 된다는걸 알기!

 

24/40

이벤트를 우리가 직접 만들어보자!

Subject에 onChangePage 이벤트를 직접!

 

App.js

    return ( // 자바스크립트의 코드로서 실행되게 하고 싶으면 {} 아니면 문자열인 ""
      <div className="App">
        <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage={function() {
            this.setState({mode: 'welcome'});
          }.bind(this)}>
        </Subject>
        <TableOfContent data={this.state.contents} />
        <Content title={_title} desc={_desc}></Content>
      </div>
    );

우리가 onChangePage라는 이벤트를 정의한 것! 저거는 mode를 welcome으로 바꾸는 함수야. 저게 props로 들어기ㅏ

 

Subject.js

import React, { Component} from 'react';

class Subject extends Component {
  // class 안에 있는 함수는 function 생략
  render() { // 필수 함수
    console.log('Subject 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;

그럼 여기서 onClick을 한다는건 a태그를 클릭했다는거지 그러면 이제 preventDefault를 하고 속성으로 있는

onChangePage 이벤트를 실행시켜! 그럼 mode가 welcome으로 바뀌겠지!

 

 

이제 id마다 맞는 desc를 출력해줄거야 그러면 각각의 id를 불러올 줄 알아야겠지?

 

TableOfContent.js

import React, { Component} from 'react';
// 없어도 되면 되는거고 있어야하면 있어야해


class TableOfContent extends Component {
  render() {
    console.log('TableOfContent Render');
    var lists = [];
    var data = this.props.data;
    var i = 0;

    while (i < data.length) {
        // key는 react가 필요해서 요청하는 것. 그냥 필요한거래
        lists.push(
            <li key={data[i].id}>
                <a 
                    href={"/content/" + data[i].id}
                    data-id={data[i].id}
                    onClick={function(e) {
                        // debugger;
                        e.preventDefault();
                        this.props.onChangePage(e.target.dataset.id);
                    }.bind(this)}
                    >
                    {data[i].title}
                </a>
            </li>);
        i = i + 1;
    }
    return (
      <nav>
        <ul>
          {lists}
        </ul>
      </nav>
    );
    
  }
}

// 어떤 것을 외부에서 사용할 수 있도록 할 것인가?
export default TableOfContent; // 이제 다른 곳에서 사용 가능@

a 태그에 dataId랑 onClick 속성!

근데 dataset이라는거 쓰려면 data- 이렇게 써야해

 

debugger;

이거 잘 이용하기 

debugger로 딱 멈춘 순간 esc 누르면 console이 나옴

그 콘솔에서 e 입력하면 현재 event에 뭐가 들어있는지 볼 수 있다

거기에서 target이 있응께 selectedContentId라는 속성을 쓸 수 있겠지! 어디서? App.js의 onChangePage()함수에서!

 

App.js

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

// 유사 자바스크립트
// JSX : "" 이런거 안따지고 쓸 수 있도록 Facebook에서 만든 유사 자바스크립트!
class App extends Component {
  constructor(props) { // state 값 초기화 그리고 세팅
    super(props); // render보다 먼저 실행되는 함수
    this.state = {
      mode: 'read',
      selectedContentId: 2,
      subject: {title: 'WEB', sub: 'This is Subject!'},
      welcome: {title: 'Welcome', desc: 'World Wide Web!'},
      contents: [
        {id: 1, title: 'HTML', desc: 'HTML is HyperText ...'},
        {id: 2, title: 'CSS', desc: 'CSS is for design'},
        {id: 3, title: 'JavaScript', desc: 'JavaScript is for interactive'}
      ]
    }
  }

  // props나 state가 바뀌면 해당 render함수가 다시 호출된다. 화면이 다시 그려진다.
  render() {
    console.log('App 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') {
      var i = 0;
      while (i < this.state.contents.length) {
        var data = this.state.contents[i];
        if (data.id === this.state.selectedContentId) {
          _title = data.title;
          _desc = data.desc;
          break; // end while
        }
        i = i + 1;
      }
      
    }

    console.log('render', this); // render 안에서 this는 App 컴포넌트 전체를 가리킨다

    return ( // 자바스크립트의 코드로서 실행되게 하고 싶으면 {} 아니면 문자열인 ""
      <div className="App">
        <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage={function() {
            this.setState({mode: 'welcome'});
          }.bind(this)}>
        </Subject>

        <TableOfContent 
          onChangePage={function(id) {
            this.setState({
              mode: 'read',
              selectedContentId: Number(id)
            });
          }.bind(this)} 
          data={this.state.contents} />

        <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}

export default App;

Number()는 숫자로 바꿔주는 JavaScript의 함수!

그러면 이제 li 클릭할 때 id의 값이 바뀌니까 render가 다시 되겠지 그때마다

break 있는 그 while문이 도니까 클릭할 때 state값이 바뀌니까 그때마다 맞느 ㄴDESC가 나오겠지!

 

그리고! bind의 매개변수를 이용하는 방법도 있다

                <a 
                    href={"/content/" + data[i].id}
                    // data-id={data[i].id}
                    onClick={function(id, num, e) {
                        // debugger;
                        e.preventDefault();
                        this.props.onChangePage(id);
                    }.bind(this, data[i].id, 10)}
                    >
                    {data[i].title}
                </a>

주석 처리하고 bind에 매개변수와 function 매개변수 저렇게 한 칸씩 밀려서 e 는 맨마지막으로@

10은 그냥 이해를 위해 넣은 것

 

 

27/40 ㅇ정리 : props vs state & 상위-하위 하위-상위 이게 제일 중요해 ***

Props

component 안에서 자신의 속성의 값을 바꿀 수 없다!

 

 

Props State 모두 render함수 호출을 유발.

UI가 바뀌어야 한다면 두 개를 이용..!!

 

상위 컴포넌트가 하위에게 영향 : PROPS

하위가 상위 : event (li 클릭하면 selectedId가 바뀌었던 것 처럼!)

 

 

https://github.com/daheeahn/190623_ReactAppReiew

 

daheeahn/190623_ReactAppReiew

인프런 생활코딩 React 1~27강 (총 40강) 까지 들은 후 만들어 본 웹사이트. Contribute to daheeahn/190623_ReactAppReiew development by creating an account on GitHub.

github.com

여기까지 만들어본 웹페이지 깃헙에 올려놓음!

 

 

 

28/40 현실 애플리케이션 만들긔!

 

출처: https://mingos-habitat.tistory.com/34 [밍고의서식지:티스토리]