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

Dico·2020년 8월 18일
1

[React.JS]

목록 보기
1/3
post-thumbnail

본 포스팅은
inflearn의 'React & Express 를 이용한 웹 어플리케이션 개발하기' 강좌 내용을 포함하고 있습니다.

링크: https://www.inflearn.com/course/react-%EA%B0%95%EC%A2%8C-velopert#


React.JS란?

React.JS는 프레임워크가 아닌 라이브러리❗️

  • 프레임워크 : 애플리케이션 구축 시 모든 애플리케이션의 공통적인 부분을 제공해줌. 필요한 기능이 이미 만들어져 있어 만들어진 '틀' 안에 '내용물'을 채워넣음으로써 완성시킴. 뼈대에 해당. 미리 만들어진 틀 밖으로 벗어나기가 어려움.
  • 라이브러리 : 필요한 부분만을 단독으로 가지고 와서 사용하는 것이 가능. 기능을 하게 하는 부품에 해당. 가벼움. React.JS는 유저 인터페이스를 만들기 위한 라이브러리!

    "React.JS is...a JavaScript library for building user interfaces."

React.JS로 Angular를 대체할 수 있을까?

  • Nope.
    Angular는 많은 기능을 이미 가지고 있는 프레임워크.
  • 하지만 같이 사용할 수는 있음. 서로 협력하는 관계.
  • 가장 좋은 방법은, Angular와 React.JS를 모두 사용해보고 필요한 곳에 적절하게 사용하는 것!

React Native 란?

  • 모바일 네이티브 앱을 React로 만들 수 있게 해주는 프레임워크.

React.JS의 핵심: Virtual DOM

  • React.JS의 핵심은 가상 DOM(Virtual DOM)
  • 실제 DOM을 직접 처리하는 행위는 처리해야하는 데이터가 많아질 경우 비효율적. 성능도 느리고 관리가 힘듦.
  • 자바스크립트 객체에 불과한 Virtual DOM을 사용할 경우 DOM API를 사용하는 것보다 처리가 훨씬 빨라짐.

React.JS의 장점은?

  • 학습이 간단하다. 컴포넌트만을 사용하기 때문에 복잡하지 않음.
  • 가상 DOM(Virtual DOM)을 사용한다.
  • 뛰어난 Garbage Collection, 메모리관리, 성능.
  • UI를 컴포넌트화 하여 매우 간편한 UI 수정 및 재사용.
  • 페이스북 개발자들이 만들어 페이스북에서 꾸준히 업데이트를 함 - 탄탄한 기반❗️
  • 다른 프레임워크나 라이브러리와 혼용 가능. 이미 개발이 완료된 서비스에도 적용이 가능.
  • *서버 & 클라이언트 사이드 렌더링 모두 지원.
    • 서버 사이드 렌더링의 장점 : 초기 렌더링을 서버 사이드 렌더링으로 할 경우, 유저에게 쾌적한 사용경험(User Experience)을 제공할 수 있음 - 클라이언트 사이드 렌더링은 초기 구동 딜레이가 있기 때문. 서버 측에서 HTML을 미리 생성해서 문자열 형태로 브라우저에 띄움. SEO(Search Engine Optimization; 검색엔진최적화)지원 가능. 다만 서버측의 자원을 쓰게 되는 것은 불가피하기 때문에 컴퓨터 성능이 좋지않고 방문자가 많다면 추천하지 않음.

React.JS의 단점은?

  • 시각적으로 보여지는 부분만 컨트롤 할 수 있다.
  • IE8 이하는 지원하지 않음.

React.JS 시작하기

  • React 파일은 컴포넌트를 담당.
  • React DOM 파일은 실제 DOM에 렌더링을 담당.
  • Babel: 자바스크립트 컴파일러. 여러가지 브라우저를 지원하기 위해 ES6로 작성된 코드를 ES5로 변환해줌.
  • 컴포넌트는 자바스크립트 클래스. 참조 시 <컴포넌트명/>형식으로 쓰임. 소문자로 쓰면 <div><span> 같은 HTML 태그로 해석되기 때문에 반드시 대문자로 시작해야함.

ES6 클래스 (Class)

  • ES6에 새로 도입된 문법. (참고로 React.createClass() 메소드를 통해 일반적인 방법으로 컴포넌트를 만들 수도 있다.)
  • React를 사용할 때는 컴포넌트를 class 또는 함수로 정의할 수 있음. React 컴포넌트 class를 정의하려면 React.Component상속받아야 함.
  • 사용 전 반드시 선언이 되어야 한다! 선언하지 않고 사용할 경우 ReferenceError 발생.
  • 생성자 메소드가 있음. JavaScript 클래스 안에서는 메소드만 만들 수 있다.
  • 타 객체형 언어들처럼 *static 메소드도 만들 수 있음.
    static 메소드는 객체로 만들기 전에도 사용할 수 있으며, 상속도 가능. 상속을 하면 super키워드를 통해 parent class를 호출할 수 있음.
    • static method: 클래스를 위한 정적(static) 메소드를 정의함. 정적 메소드는 클래스의 인스턴스화(instantiating) 없이 호출되며, 클래스의 인스턴스에서는 호출할 수 없다. 주로 어플리케이션(application)을 위한 유틸리티(utility) 함수를 생성하는데 사용된다.
      -MDN
//ES6 class 예시 - Codelab 컴포넌트 만들기 
class Codelab extends React.Component { 
  render() {
    return(
      <div>Codelab</div>
    ); 
  }
}
  • extends React.Component: ES6 클래스를 사용해서 컴포넌트를 만드는 방법. 말 그대로 React.Component 클래스를 상속함.
  • 이렇게 만들어진 컴포넌트는 또 다른 컴포넌트에서 사용할 수도 있음.
  • 모든 React 컴포넌트는 render() 메소드가 있음. 이 메소드는 컴포넌트가 어떻게 생길 지 정의를 해준다.

JSX(Javascript XML)의 특징

  • React JSX: JavaScript언어의 확장. JavaScript에서 HTML형식을 그대로 사용할 수 있게 하는 등 XML과 같은 문법을 native JavaScript로 변환해줌.
//JSX
var a = (
    <div>
  	welcome to <b>React CodeLab</b>
    <div>
  );
/* ()를 사용하지 않아도 오류는 발생되지 않지만 가독성을 위해 사용을 권장 */

⬇️⬇️⬇️

//native JavaScript
'use strict';

var a = React.createElement(
 "div", 
 null, 
 "Welcome to", 
 React.createElement(
   "b",
   null, 
   "React.js CodeLab"
   )
 );
  • JSX 작동은 Babel(트랜스파일링 프로그램: 브라우저가 해석이 가능한 코드로 변환)이 해줌.
  • Babel에서 JSX Loader를 사용해 JSX 형태의 코드를 변환해주는 것.
  • ReactDOM.render(): 실제 페이지에 JSX 형태의 코드를 렌더링할 때 사용된다. 첫번째 인자는 '렌더링 하고자하는 JSX형태 코드'. 두번째 인자는 '이 컴포넌트를 렌더링 할 엘리먼트'.
<!--HTML divider-->
<div id="root"></div>
//App 컴포넌트 
class App extends React.Component {
  render() {
    return (
      <Codelab/>  /*App 컴포넌트가 Codelab 컴포넌트를 보여준다.*/
    );
  }
}

//ReactDOM.render() 예시
ReactDOM.render(<App/>, document.getElementById('root'));
  • JSX의 주요특징 4가지
  1. Nested elements inside of container element
  2. Braces{} JavaScript Expression
  3. Style with camelCase Object
  4. Comments synthesis
  1. Nested Element:
    모든 JSX 형태의 코드는 container element 안에 포함시켜야 한다. 무언가로 감싸져야만 코드가 제대로 작동함.
//에러발생
render() { 
  return (
    <h1>Hello</h1>
    <h2>This is an error</h2>
    )
}

//올바른 코드: container element <div> 태그 포함
render() { 
  return (
    <div>
    	<h1>Hello</h1>
    	<h2>Yay, the error is gone!</h2>
    </div>
    )
}
  1. JavaScript Expression:
    JSX안에서 JavaScript 를 표현할 때는 {} 으로 wrapping을 해야한다.
render() {
  let text = "Hello World!"; 
  return (
    //text 변수를 {} 으로 감싸주기
    <div>{text}</div>
    );
}
  1. Inline Style:
    Style을 설정할 때는 (String 형식을 사용하지 않고) key가 camelCase인 객체를 사용해야 한다.
//key가 camelCase인 객체 사용
render() { 
  let style = { 
    color: '#f5f6fa',
    fontSize: '50px',
    backgroundColor: '#f6b93b'
  };
  
  //여기서도 style변수는 {}으로 감싸주기
  return (
    <div style={style}>Hello World</div>
  );
}


//class를 설정할 때는 class= 가 아닌 className= 을 사용하기
render() { 
  return (
    <div className='box'>Hello World</div>
  ); 
}
  1. Comments:
    주석을 작성할 떄는 {/* ... */} 형식 안에 작성하기.
    *주의: 주석 역시 Nested Element 로 container element 내부에 작성되어야 함.
//comment가 container element인 <div>tag 밖으로 넘어가면 error 발생
render() { 
  return (
    <div>
    {/*This is how you write the comment*/}
    {/*Multi-line
    	testing*/}
	Hello Strangers
    </div>
   ); 
}

props 란?

  • 컴포넌트 내부의 Immutable data, 변화하지 않는 데이터(정적인 화면구성)를 처리할 때 사용됨.
  • 상위 컴포넌트에서 하위 컴포넌트로 데이터를 넘겨줄 때 사용.
  • JSX 내부에 {this.props.propsName}
  • 컴포넌트를 사용할 때, HTML태그에 값을 전달하듯 <> 괄호 안에 propsName = "value(값)"형식으로 작성.
  • this.props.children은 모든 컴포넌트가 기본적으로 갖고있는 props로서, <컴포넌트명></컴포넌트명> 사이의 값이 들어감.
//Codelab컴포넌트 (하위)
class Codelab extends React.Component { 
  render() {
    return (
      <div>
        <h1>Hello {this.props.name}</h1> /*velopert*/
        <div>{this.props.children}</div> /*여기에 보여지는 것이 바로 props.children*/
      </div>
    ); 
  }
}


//App 컴포넌트 (상위)
class App extends React.Component {
  render() {
    return (
      <Codelab name="velopert">여기에 보여지는 것이 바로 props.children</Codelab>
    );
  }
}


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

Output ➡️

한 단계 더 나아가 아래와 같이 App 컴포넌트의 <Codelab name=" velopert"> velopert라는 text 대신에 {this.props.name}을 넣어 또 다른 props를 설정할 수 있다.
그리고 위 예제에서 여기에 보여지는 것이 바로 props.children이라고 보여지는 곳에 {this.props.children}을 대신해 자체적으로 props를 만들어줄 수도 있다.

//Codelab컴포넌트 
class Codelab extends React.Component { 
  render() {
    return (
      <div>
        <h1>Hello {this.props.name}</h1>
        <div>{this.props.children}</div>
      </div>
    ); 
  }
}


//App 컴포넌트 
class App extends React.Component {
  render() {
    return (
      <Codelab name={this.props.name}>{this.props.children}</Codelab> 
    );
  }
}


ReactDOM.render(<App name=" velopert">I am your child</App>, document.getElementById('root'));

Output ➡️

Props 기본값 설정하기

  • Component.defaultProps = {...}

기본값을 설정할 때는 컴포넌트 선언이 끝난 후, defaultProps객체를 설정하면 된다.

//App 컴포넌트
class App extends React.Component {
  render() {
    return (
      <div>{this.props.value}</div>
      );
  }
};

//defaultProps 객체
App.defaultProps = {
  value: 0           /*value props의 기본값을 0으로 설정*/
};

Type 검증하는 방법

  • Component.propTypes ={...}

이 기능으로 특정 props값이 특정 type이 아니거나, 필수 props인데 입력하지 않았을 경우, console창에서 경고를 표시하도록 할 수 있다.
type를 검증할 때는 컴포넌트 선언이 끝난 후, props.propTypes 객체를 설정하면 된다.

//App 컴포넌트
class App extends React.Component {
  render() {
    return (
      <div>
      	{this.props.value}
      	{this.props.secondValue}
  	{this.props.thirdValue}
     </div>
    );
  }
};

//propTypes 객체
App.propTypes = {
  value: React.PropTypes.string,  /*첫번째 값은 string타입*/
  secondValue: React.PropType.number,   /*두번째 값은 number타입*/
  thirdValue: React.PropTypes.any.isRequired   /*세번째 값은 타입상관없이 필수입력*/
};
  

isRequired가 입력되면 필수입력항목으로 지정된다.
propTypes를 지정하는 것은 필수가 아니다. 그러나 유지보수와 효과적인 활용을 위해서 설정하는 것.
대표적인 예로 여러가지 컴포넌트를 사용하는 프로젝트를 하는 경우, 각각의 컴포넌트가 하는 어떤 props를 필요로 하고, 어떤 type이어야 하는지 빠르게 파악할 수 있도록 도움.

Example

//Codelab컴포넌트 
class Codelab extends React.Component { 
  render() {
    return (
      <div>
        <h1>Hello {this.props.name}</h1>
        <h2>{this.props.number}</h2>  
        <div>{this.props.children}</div>
      </div>
    ); 
  }
}

//Codelab 컴포넌트 propType 설정
Codelab.propTypes = {
  name: PropTypes.string, 
  number: PropTypes.number.isRequired
};

//Codelab 컴포넌트 기본값 설정 
Codelab.defaultProps = {
  name:'Unknown'
}

//App 컴포넌트 
class App extends React.Component {
  render() {
    return (
      <Codelab name={this.props.name} number={this.props.number}>{this.props.children}</Codelab>
    );
  }
}


ReactDOM.render(<App name={'Scarelet'} number={25}>You are such a lovely person!</App>, document.getElementById('root'));

Output ➡️

states 란?

  • 유동적인 데이터 (동적인 화면구성)
  • JSX내부에 {this.state.stateName}
  • 초기값 설정이 필수, 생성자(constructor) 안에서 this.state ={}으로 설정.
  • 다만 렌더링 된 다음엔 this.state ={}절대 재사용하지 말 것.
  • 렌더링 이후에 값을 수정할 때에는 컴포넌트 내부에서 this.setState({})로 변경이 가능하다. 달리 말하면, 생성자에서는 사용이 안된다는 뜻. 성능이 떨어짐.
class Counter extends React.Component {
  
  //초기값 설정
  constructor(props){ /*props는 Counter가 만들어질 때 전달받을 매개변수*/
    super(props); /*super를 통해 React.Component를 먼저 실행해 접근성을 확보*/
    this.state = {
      value: 0
    }
    this.handleClick = this.handleClick.bind(this);/*this binding 해주기*/
  }
  
  //버튼이 클릭될 때 실행될 메소드 
  handleClick(){
    this.setState({ /*binding을 해주지 않으면 this가 뭔지 모른다!*/
      value: this.state.value + 1
    })
  }
  
  
  render() {
    return (
      <div>
        <h2>{this.state.value}</h2>
        <button onClick={this.handleClick}>Press Me</button> 
      </div>
    )
  }
}

class App extends React.Component {
  render() {
    return (
      <Counter/>
    );
  }
};

ReactDOM.render(
  <App></App>,
  document.getElementById("root")
);
  • super(props); 로 상속받은 class인 React.Component(Parent의 생성자 메소드)를 먼저 실행시킨다. 이 과정이 먼저 실행되어야 this.state와 같은 메소드에 접근할 수 있음.
  • 리액트에서 사용하는 이벤트 시스템은 브라우저에서 사용되는 자바스크립트 네이티브 이벤트와 똑같은 인터페이스를 가지고 있음. 따라서 onClick을 그대로 사용해서 클릭이벤트를 추가할 수 있음.
  • <button onClick={this.handleClick.bind(this)}>Press Me</button>handleClick()에서 사용되는 thisrender()에서 사용되는 this같다는 뜻이 된다. 이렇게 binding을 해주지 않으면handleClick()내부의 this가 무엇인지 모르기 때문. 이렇게도 binding이 가능하나, 관습적으로 위 예시와 같이 Constructor 내부(this.handleClick = this.handleClick.bind(this);)에 binding 해주는 것이 나음.
  • 주의할 점은 버튼을 추가하는 부분(<button onClick={this.handleClick}>Press Me</button>)에서 handleClick괄호없이 기재되어야만 불필요한 실행을 방지할 수 있다는 것이다.

컴포넌트 매핑(Component Mapping)이란?

  • 비슷한 코드를 반복해서 렌더링하는 방법
  • 데이터 배열을 리액트에서 렌더링할 때는 JavaScript의 map()메소드를 사용.
    +PLUS: map()메소드는 매개변수로 전달 된 함수를 통해 배열의 각 요소를 처리해서 그 결과로 새로운 배열을 생성한다.

    arr. map(callback, [thisArg])

  • callback: 새로운 배열의 요소를 생성하는 함수로서, 세가지 인수(currentValue, index, array)를 매개변수로 받는다.
  • thisArg: (선택항목) callback함수 내부에서 사용할 this 값을 설정
class Contactinfo extends React.Component {
  render() { /*객체형 props를 사용해 이름과 번호를 렌더링*/
    return ( 
       <div>
        {this.props.contact.name}{this.props.contact.phone}
      </div>
    )
  }
}

class Contact extends React.Component {
  /*생성자 메소드에서 state초기설정*/
  constructor(props){
    super(props);
    this.state = {
      contactData: [
        {name: '김수환무', phone: '010-1111-2222'},
        {name: '거북이', phone: '010-1111-3333'},
        {name: '두루미', phone: '010-1111-4444'},
        {name: '삼천갑자', phone: '010-1111-5555'}
      ]
    }
  }
  render() {
     const mapToComponent = (data) => {
       /*새로운 배열을 만들어서 리턴*/
       return data.map((contact, i) => {
         return (<Contactinfo contact = {contact} key = {i}/>)
       })
     }
    return ( 
      /*반복되는 부분을 또 다른 컴포넌트로 생성(Contactinfo)*/
      /*mapToComponent 함수사용가능. (this.state.contactData)는 매개변수*/
      <div> 
       {mapToComponent(this.state.contactData)}
      </div>
    )
  }
}


class App extends React.Component {
  render() {
    return (
      <Contact/> /*Contact 컴포넌트 렌더링*/
    );
  }
};

ReactDOM.render(
  <App></App>,
  document.getElementById("root")
);
  • return (<Contactinfo contact = {contact} key = {i}/>) })에서 key = {i}를 사용하는 이유는 각 데이터에 아이덴티티(identity)를 주기 위해서.

Reference

*본 포스팅은 아래 사이트들을 참고 및 인용하여 작성되었습니다.
학습단계로 잘못된 정보가 있을 수 있습니다. 잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다 😊
https://m.blog.naver.com/manddonara/119738492
https://moolgogiheart.tistory.com/87
https://ko.reactjs.org/docs/react-component.html
https://medium.com/@yeon22/react-js-react-js%EC%9D%98-props-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95-bc59a5c257a
https://medium.com/@ljs0705/babel-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-a1d0e6bd021a

profile
프린이의 코묻은 코드가 쌓이는 공간

4개의 댓글

감사합니다 ㅜㅜ 진짜진짜 도움많이 됐어요!

1개의 답글
comment-user-thumbnail
2021년 7월 23일

감사합니다 잘보구가여!!
SI 업체 다닌지 1년 조금 넘어가는데..
백엔드 담당인데 프론트도 이것저것 공부해야해서 빡시네여!! ㅜㅜ
저두 얼른 코더가 아닌 개발자가 될수있기를.. .

답글 달기
comment-user-thumbnail
2024년 2월 12일

와.... 이제 막 시작해서 이해가 100프로까진 아니어도 많은 도움됐어요ㅠㅠ 감사합니다

답글 달기