본문 바로가기

Programming/국비학원

220801 - 리액트

리액트 문법

https://velog.io/@edie_ko/React-JSX%EB%9E%80-%EB%A0%8C%EB%8D%94%EB%A7%81-Rendering%EC%9D%B4%EB%9E%80

 

React | JSX란? 렌더링 Rendering이란?

JSX를 정리하기에 앞서 간단히 리액트를 정리해보자. 리액트는 페이스북이 만든 사용자 UI 구축을 위한 라이브러리이다. 하나의 단일 url을 가지고 SPA(Single Page Application)으로 사이트를 표현하는

velog.io

https://medium.com/react-native-seoul/react-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%B2%98%EC%9D%8C%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90-01-react-js%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-ad8ba252ee28

 

[React] 리액트를 처음부터 배워보자. —01. React.js란 무엇인가?

이 글을 남기는 계기는 Dan Ambramov의 블로그 Overreacted를 보며 React.js에 대해 더 깊이 공부할 필요성을 느꼈기 때문이다.

medium.com

https://medium.com/react-native-seoul/react-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%B2%98%EC%9D%8C%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90-02-react-createelement%EC%99%80-react-component-%EA%B7%B8%EB%A6%AC%EA%B3%A0-reactdom-render%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-41bf8c6d3764

 

[React] 리액트를 처음부터 배워보자. — 02. React.createElement와 React.Component 그리고 ReactDOM.render의

이 글을 남기는 계기는 Dan Ambramov의 블로그 Overreacted를 보며 React.js에 대해 더 깊이 공부할 필요성을 느꼈기 때문이다.

medium.com

https://velog.io/@soyi47/React-Component-props-state

 

[React] Component와 props, state

🚀 Component, props, state에 대해 알아본다.

velog.io

https://velog.io/@grinding_hannah/React.JS-React-%EA%B0%95%EC%A2%8C-%ED%95%99%EC%8A%B5%EB%82%B4%EC%9A%A9-%EC%A0%95%EB%A6%AC

 

[React.JS] React 기초 학습내용 정리

본 포스팅은 inflearn의 'React & Express 를 이용한 웹 어플리케이션 개발하기' 강좌 내용을 포함하고 있습니다.링크: https://www.inflearn.com/course/react-%EA%B0%95%EC%A2%8C-velopert프레임워

velog.io

 

 

React.js => MVC 패턴, MVVM패턴 중 View

              => 사용자가 조작하기 위한 UI를 만드는 것을 도와주는 라이브러리

 

 

1. JSX 문법 : 자바스크립트 안에서 html 문법 사용 

( => React.createElement()를 호출하기 위한 방법일 뿐, Babel(js 트랜스파일러)을 통해 파싱되고 트랜스 파일링됨 )

 - 속성은 쌍따옴표로 감싸기 ex. className="a"

 - 태그는 항상 닫아야 함

 - 모든 태그는 self-closing 가능 ex. <input />

 - 가장 외곽에 wrap할 태그 필요 (형제 노드 작성 불가)

 

- render 안에서 js 변수 정의, return 에서 중괄호 감싸며 표현

 

 - Element Rendering : html요소(element) 또는 React요소 등의 코드가 눈으로 볼 수 있도록 그려지는 것

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

엘러먼트는 화면에 표시할 내용을 담음.

브라우저 DOM 엘리먼트와는 다르게 React 엘리먼트는 일반 객체이며 쉽게 생성 가능

React DOM은 React 엘리먼트와 일치하도록 DOM을 업데이트함

ReactDOM.render 함수 => React 요소가 DOM node에 추가되어 화면에 렌더됨

첫 번째 인자: JSX로 넘길 React 요소 인자

두 번째 인자: 첫번째 인자를 렌더할 container(부모요소) 인자

 

 

2. Component 및 재사용성

컴포넌트 : 독립적인 단위의 소프트웨어 모듈

웹에서 쓰는 각 요소들을 컴포넌트로 생성 -> 기존의 UI를 다른 화면, 다른 프로젝트에서 재사용 가능

함수형 :  return문에서 JSX를 반환

클래스형 : React.Component 클래스를 상속 / 컴포넌트는 jsx를 반환해야 하는데, 클래스는 return문 사용 불가 -> render()함수를 이용해 return 작성

 


3. Virtual DOM

메모리 단에서 컴포넌트 정보를 생성하고 비교 -> 전체 DOM 트리가 업데이트가 필요한 경우 이를 반영하는 방식

바뀌지 않은 부분과 바뀐 부분을 자동으로 감지해서 업데이트

 

 

4. states, props

props : 부모 컴포넌트가 자식 컴포넌트에게 주는 값 / 자식 컴포넌트에서는 받아온 props 를 직접 수정 불가, event 이용해 수정 가능

ex. <Dog name="Ari" age={10} />

state : 컴포넌트 내부에서 선언, 내부에서 값 변경 가능

클래스형 컴포넌트 - 컴포넌트 자체가 state를 지니는 방식으로 사용

함수형 컴포넌트 - useState, Hook을 통해 사용

 

 

5. 선언형

컴포넌트(원하는 결과, 뷰)를 얻기 위해 jsx 문법을 이용

즉, jsx를 얻기 위한 구체적 알고리즘에 대한 구현 X

ex. document.createElement / 컴포넌트의 변경사항을 체크하는 알고리즘 / 리-렌더링 여부에 대한 알고리즘 구현 X

 

 

 

  •  
  • App.js (수정 전)

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

class App extends Component{
  render(){
    return ( 
      <div className='App'> 
        <Subject title='웹 카페' sub='웹에 대해 알아봅시다!'></Subject> 
        <Subject title='리액트' sub='리액트에 대해 알아봅시다'></Subject>
        <TOC></TOC>
        <Content title='HTML5에 대해' desc='홈페이지의 뼈대를 말한다'></Content>
      </div>
      );
  }
}

export default App;

 

 

  • 수정 후

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

class App extends Component{
  
  constructor(props){ //컴포넌트가 render 되기 전 props 값으로 보낼 속성값(subject) 초기화
    super(props); 
    this.state={ //state: 상태값 저장
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'}  //subject state 생성
    }
  }

  render(){ //JSW 반환 위해 작성 (return문 작성)
    return ( //제작한 JSX 컴포넌트 넣기
      <div className='App'> 
        <Subject title={this.state.subject.title}  /* this=App / 중괄호 필수 */
        sub={this.state.subject.sub}></Subject> 
        <TOC></TOC>
        <Content title='HTML5에 대해' desc='홈페이지의 뼈대를 말한다'></Content>
      </div>
      );
  }

}

export default App;

 

 

 

  • 컴포넌트에 state 전달 (props로?)
  • App.js

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

class App extends Component{
  
  constructor(props){ //속성 초기화
    super(props);
    this.state={ //state: 상태값
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ 
    return ( //제작한 컴포넌트 넣기
      <div className='App'> 
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        <TOC data={this.state.contents}></TOC>
        <Content title='HTML5에 대해' desc='홈페이지의 뼈대를 말한다'></Content>
      </div>
      );
  }

}

export default App;

 

 

  • TOC.js

import { Component } from 'react';

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

    return(
      <nav> 
        <ul>
          {lists}
        </ul>
      </nav>
    );
  }
}

export default TOC;

 

 

 

  •  
  • App.js

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'welcome', //read로 변경하면 html5 설명 나옴
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){  //state 값 바뀌면 render 함수 재호출
    console.log('App 컴포넌트 렌더링됨');
    let _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> 
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

  • Subject.js

import { Component } from 'react';


class Subject extends Component{
  render(){
    console.log('Subject 컴포넌트가 렌더링됨');
    return(
      <header>
        <h1><a href='/'>{this.props.title}</a></h1>
        <p>{this.props.sub}</p>
      </header>
    );
  }
}


export default Subject;

 

 

  • Content.js

import { Component } from 'react';

class Content extends Component{
  render(){
    console.log('Content 컴포넌트가 렌더링됨');
    return(
      <article>
        <h2>{this.props.title}</h2>
        <p>{this.props.desc}</p>
      </article>
    );
  }
}

export default Content;

 

 

  • TOC.js

import { Component } from 'react';

class TOC extends Component{
  render(){
    console.log('TOC 컴포넌트가 렌더링됨');
    let lists=[];
    let data=this.props.data;
    let i=0;
    while(i<data.length){
      lists.push(<li key={data[i].id}><a href={"/content/"+data[i].id}>{data[i].title}</a></li>);
      i++;
    }

    return(
      <nav> 
        <ul>
          {lists}
        </ul>
      </nav>
    );
  }
}

export default TOC;

 

 

 

  • event 처리
  • App.js

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'welcome', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; 
    if (this.state.mode==='welcome'){  //this=App
      _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 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject>  
        */}
        <header> 
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              debugger; //브라우저가 해당 시점 코드에서 멈춤, 소스로 자동 이동
              alert('안녕하세요');
              }}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>         
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;

 

 

=>h1 클릭시 새로 고침됨 / but 리액트는 내용만 바뀌는 걸 지향 (SPA)

=> a 클릭시 새로고침되는 기본이벤트 제거 

 

=>

  •  

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'read', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){ //render: export 도움
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){  //this=App
      _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 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        */}
        <header>
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              event.preventDefault(); 
              }}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>        
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;

 

 

 

=>h1 클릭 시 내용 바꾸기

 

=>

  •  

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'read', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){ //render: export 도움
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){  //this=App
      _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 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        */}
        <header>
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              event.preventDefault();
              this.state.mode='welcome'; //state undefined 에러 발생 
              }}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>        
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;

 

 

 

=> 에러 발생

=>

  • bind로 함수-this 연결

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'read', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){ //render: export 도움
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){  //this=App
      _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 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        */}
        <header>
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              event.preventDefault();
              this.state.mode='welcome'; //state undefined 에러 발생 => this의 주체가 없음
              }.bind(this)}>  //function을 this와 연관시킴
              {this.state.subject.title}
            </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>        
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;

 

 

=> this 연결해도 클릭 시 변화 X

=> 값을 mode에 넣었지만 리액트가 인지 못해서 다시 render 안 함

=>

  •  

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'read', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},//
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){ //render: export 도움
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){  //this=App
      _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 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        */}
        <header>
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              event.preventDefault();
              this.setState({   //생성자에서 이미 setting된 값을 동적으로 바꿀 때 사용
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
            </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>        
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;

 

 

 

  •  
  • App.js

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

class App extends Component{
  
  constructor(props){ //컴포넌트의 속성 초기화
    super(props);
    this.state={ //state: 상태값
      mode:'read', 
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  //state 값 바뀌면 render 함수 재호출
  render(){ //render: export 도움
    console.log('App 컴포넌트가 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){  //this=App
      _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);  //렌더의 주체 :App 컴포넌트

    return ( //제작한 컴포넌트 넣기
      <div className='App'> 
        {/* Subject 컴포넌트 잠시 사용 안 함
        <Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject> 
        */}
        <header>
          <h1>
            <a href='/' onClick={function(event){
              console.log(event);
              event.preventDefault();
              console.log('event in',this); //주체 App
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
            </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>        
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }

}

export default App;