다라다라V
article thumbnail
Published 2022. 10. 15. 01:22
[React] 03. 컴포넌트 프레임워크/REACT
728x90
반응형

앞선 포스트에서 컴포넌트(component)는 리액트 프로젝트에서 특정 부분이 어떻게 생길지를 결정하는 선언체라고 배웠습니다. 리액트의 컴포넌트는 함수형 컴포넌트 클래스형 컴포넌트로 두 가지로 선언될 수 있습니다.

클래스형 컴포넌트와 함수형 컴포넌트를 비교하며 컴포넌트를 생성해보겠습니다. 또한 컴포넌트에서 사용하거나 렌더링 하는 데이터를 담는 props와 state의 차이점과 선언 방식을 배우겠습니다.

1. 📌 클래스형 컴포넌트

1.1. 📚 클래스형 컴포넌트

컴포넌트를 선언하는 방식은 클래스 컴포넌트와 함수 컴포넌트로 나뉩니다. 클래스형 컴포넌트와 함수 컴포넌트는 state 기능 및 라이프 사이클 기능, 임의 메서드 정의 등에서 차이가 납니다.

각 방법으로 작성된 코드를 보면서 차이점을 비교해보자.

 

1.1.1. 📃 클래스 컴포넌트

<javascript />
import {Component} from "react"; class App extends Component { render() { const name = 'react'; return <div className='react'> {name} </div>; } } export default App;

 

1.1.2. 📃 함수 컴포넌트

<javascript />
import './App.css'; function App() { const name = "리액트"; return <div className='react'> {name} </div>; } export default App;

 

함수 컴포넌트의 특징은 다음과 같습니다.

  • 클래스 컴포넌트보다 선언하기 편리
  • 클래스 컴포넌트보다 메모리 자원을 덜 사용하고, 실제 배포할 때도 결과물의 파일 크기가 더 작습니다.
  • 리액트 v16.8 업데이트로 state와 라이프사이클 API도 사용이 가능해졌습니다.

 

리액트 v16.8 업데이트로 Hooks가 도입되었고 함수 컴포넌트도 클래스 컴포넌트와 같이 작업을 할 수 있게 되었습니다. 리액트 공식 매뉴얼에서는 함수 컴포넌트와 Hooks를 사용하도록 권장합니다. 그러나 이전의 작성된 코드들의 유지 및 보수를 위하여 클래스 컴포넌트도 반드시 알아두어야합니다.


2. 📌 첫 컴포넌트 생성

2.1. 📚 함수 컴포넌트 작성하기

 

컴포넌트는 다음의 세 단계를 거쳐서 만들 수 있습니다.

  1. 파일 만들기
  2. 코드 작성하기
  3. 모듈 내보내기 및 불러오기

VS 코드에서 파일을 만드는 방법은 src 디렉터리 - [우클릭] - <파일이름>.js 작성하면 됩니다.


2.2. 📚 코드 작성하기

 

앞으로는 NewComponent.js 파일을 새로 만들어 코드 작업을 진행하도록 하겠습니다.

<javascript />
// NewComponent.js const NewComponent = () => { return <div> 화살표 함수를 이용한 컴포넌트 </div> }; export default NewComponent;

 

위 코드는 화살표 함수를 이용하여 만든 함수 컴포넌트입니다. JavaScript ES6 문법에서 function 키워드 외에도 화살표 함수로 함수를 선언하여 사용할 수 있습니다. 화살표 함수는 값을 연산하여 바로 반환해야할 때 사용하면 가독성을 높일 수 있습니다.


2.3. 📚 모듈 내보내기 및 불러오기

2.3.1. 📃 모듈 내보내기

<javascript />
export default NewComponent;

 

이 코드는 다른 파일에서 이 파일을 import 할 때, 위 클래스를 불러오도록 합니다

 

2.3.2. 📃 모듈 불러오기

<javascript />
// App.js import NewComponent from "./NewComponent"; const App = () => { return <NewComponent /> } export default App;

 

import 키워드를 통해 NewComponent 컴포넌트를 불러 새로 렌더링할 수 있습니다.


3. 📌 props

3.1. 📚 props 값 사용

props는 properties의 줄임말로 컴포넌트의 속성을 설정할 수 있습니다. 이 props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있습니다.

 

3.1.1. 📃 JSX 내부에서 props 렌더링

NewComponent.js에 다음의 내용을 작성합니다. 

<javascript />
// NewComponent.js const NewComponent = props => { return <div> {props.prog}에서 컴포넌트를 만듭니다. </div> }; export default NewComponent;
  • 해당 컴포넌트에서 program이라는 props를 렌더링하도록 하는 코드
  • props 값은 매개변수(파라미터)로 사용

 

3.1.2. 📃 컴포넌트를 사용할 때 props 값 지정하기

NewComponent를 불러오는 부모 컴포넌트(App.js)에 다음의 내용을 작성합니다.

<javascript />
// App.js import NewComponent from "./NewComponent"; const App = () => { return <NewComponent prog="리액트" />; }; export default App;
  • 부모 컴포넌트에서 props의 값을 지정

3.2. 📚 props 기본값 설정: defaultProps

위의 부모 컴포넌트의 prog 값을 지우면 prog 자리에 아무 내용도 출력되지 않습니다. props 값을 따로 지정하지 않았을 때 보여줄 기본값은 defaultProps로 설정할 수 있습니다. .

<javascript />
// NewComponent.js const NewComponent = props => { return <div> {props.prog}에서 컴포넌트를 만듭니다. </div>; }; NewComponent.defaultProps = { prog : "REACT" } export default NewComponent;

NewComponent.js 파일에 defaultProps을 이용해 기본 값을 설정해줄 수 있습니다.


3.3. 📚 태그 사이의 내용을 보여주는 children

리액트에서는 컴포넌트 태그 사이의 내용을 보여주는 props도 있습니다. children이라는 값을 통해 태그 사이에 작성한 내용을 자식 컴포넌트 내부에서 보여줄 수 있습니다. 자식 노드에서는 props.children을 통해 접근할 수 있습니다. 

(코드 내의 (...) 은 새로 작성된 부분 외의 코드는 이전에 작성한 코드와 동일함을 의미합니다.)

<javascript />
// NewComponent.js const NewComponent = props => { return ( <div> {props.prog}에서 컴포넌트를 만듭니다. <br/> children의 값은 {props.children}입니다. </div> ); }; (...) export default NewComponent;
<javascript />
// App.js import NewComponent from "./NewComponent"; const App = () => { return <NewComponent> ~태그 사이~ </NewComponent> } export default App;

3.4. 📚 비구조화 할당 문법을 통해 props 내부 값 추출하기

props 값을 조회할 때마다 props.prog, props.children 같이 prog. 이라는 키워드가 필요합니다. ES6의 비구조화 할당 문법을 사용하여 내부 값을 더 편히 추출할 수 있습니다.

<javascript />
// NewComponent.js const NewComponent = props => { const {prog, children} = props; return ( <div> {prog}에서 컴포넌트를 만듭니다. <br/> children의 값은 {children}입니다. </div> ); }; (...) export default NewComponent;
  • 객체에서 값을 추출하는 문법을 비구조화 할당(destructing assignment)라고 부름
  • 구조 분해 문법이라고도 불림

 

함수의 파라미터 부분에서도 사용 가능합니다. 함수의 파라미터가 객체라면 값을 바로 비구조화하여 다음과 같이 코드를 작성할 수 있습니다.

<javascript />
// NewComponent.js const NewComponent = ({prog, children}) => { return ( <div> {prog}에서 컴포넌트를 만듭니다. <br/> children의 값은 {children}입니다. </div> ); }; (...) export default NewComponent;

3.5. 📚 propTypes를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 타입을 지정할 때는 propTypes를 사용합니다. propTypes를 지정하는 방법은 defaultProp을 설정하는 것과 비슷합니다. propTypes을 사용하기 위해 코드 상단에 import를 해야합니다.

<javascript />
import PropTypes from 'prop-types';

 

3.5.1. 📃 타입 설정하기 

<javascript />
// NewComponent.js import PropTypes from 'prop-types'; (...) NewComponent.propTypes = { prog: PropTypes.string }; export default NewComponent;

 

  • prog의 내용은 반드시 String으로 지정되어야 함
  • 잘못된 타입으로 값을 지정한 뒤 개발자 도구의 Console 탭을 열면 오류 창이 뜸

 

3.5.2. 📃 isRequired를 사용하여 필수 propTypes 설정

propTypes을 지정할 때 경고 메세지를 발생시킬 수 있습니다. 

<javascript />
// NewComponent.js import { PropTypes } from "prop-types"; const NewComponent = ({prog, children, age}) => { return ( <div> {prog}에서 컴포넌트를 만듭니다. <br/> children의 값은 {children}입니다. <br/> 저의 나이는 {age}세 입니다. </div> ); }; NewComponent.defaultProps = { prog : "리액트" } NewComponent.propTypes = { prog: PropTypes.string, age: PropTypes.number.isRequired }; export default NewComponent;

 

부모 컴포넌트인 App.js에서 age의 값이 설정되지 않는 다면 콘솔창에서 오류 메시지를 보여줄 것 입니다.

<javascript />
// App.js import NewComponent from "./NewComponent"; const App = () => { return( <NewComponent prog = "React" age = {100} > ~ children 값 ~ </NewComponent> ) } export default App;

 

3.5.3. 📃 PropTypes의 종류

https://github.com/facebook/prop-types  에서 PropTypes에 대한 내용을 볼 수 있습니다.


3.6. 📚 클래스형 컴포넌트에서 props 사용하기

클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 됩니다. defaultProps와 propTypes는 똑같은 방식으로 설정할 수 있습니다. 클래스형 컴포넌트에서 props 값을 조회하는 코드입니다.

<javascript />
// NewComponent.js import { Component } from "react"; import PropTypes from "prop-types"; class NewComponent extends Component { render() { const {prog, children, age} = this.props; //비구조화 할당 return ( <div> {prog}에서 컴포넌트를 만듭니다. <br/> children의 값은 {children}입니다. <br/> 저의 나이는 {age}세 입니다. </div> ) } } NewComponent.defaultProps = { prog : "리액트" } NewComponent.propTypes = { prog: PropTypes.string, age: PropTypes.number.isRequired }; export default NewComponent;

 

defaultProps와 propTypes는 class 내부에서도 지정 가능합니다.

<javascript />
// NewComponent.js import { Component } from "react"; import PropTypes from "prop-types"; class NewComponent extends Component { static defaultProps = { prog : "리액트" }; static propTypes = { prog: PropTypes.string, age: PropTypes.number.isRequired } render() { ( ... ) } } export default NewComponent;

4. 📌 state

4.1. 📚 state

  • state 컴포넌트 내부에서 바뀔 수 있는 값을 의미
  • props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하며 자신은 해당 props를 읽기 전용으로만 사용
  • state는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트 할 수 있음
  • 일반 변수는 값이 변경될 때 html에 자동 변경되지 않지만, state는 값이 변경되면 html에 재랜더링 해줌
    => 값의 변화가 자주 있을 때 state를 사용
  • 클래스형 컴포넌트는 state, 함수 컴포넌트에서는 useState를 사용

4.2. 📚 클래스형 컴포넌트의 state

클릭으로 숫자를 늘이는 Counter.js를 만들어 봅시다.

<javascript />
// Counter.js import { Component } from "react"; class Counter extends Component { constructor(props) { super(props); this.state = { number: 0 // state 초깃값 설정하기 }; } render() { const {number} = this.state; // state 조회시 this.state를 조회 return ( <div> <h1> {number} </h1> <button /* onClick 함수를 사용하여 클릭 시 숫자를 늘려주는 버튼 만들기 */ onClick = {() => { /* this.setState를 사용하여 state에 새로운 값을 지정 */ this.setState( {number: number +1 } ); }} > +1 </button> </div> ); } } export default Counter;

4.3. 📚 함수 컴포넌트에서 useState 사용하기

4.3.1. 📃 배열 비구조화 할당

  • 배열 비구조화 할당 객체 비구조화 할당과 비슷함
  • 배열 안에 들어있는 값을 쉽게 추출하도록 하는 문법
  • Destructing 문법을 통해 형태를 맞추어 값을 쉽게 할당
<javascript />
const array = [1, 2]; const one = array[0]; const two = array[1];

위 코드는 배열 비구조화 할당을 통해 더 간단히 표현될 수 있습니다.

<javascript />
const array = [1, 2]; const [one, two] = array;

 

4.3.2. 📃  useState 사용하기

리액트 16.8 이전 버전에서는 함수 컴포넌트에서 state를 사용할 수 없었습니다. 그러나 업데이트 이후, Hooks가 생기면서  useState 함수를 사용하여 함수 컴포넌트에서도 state를 사용할 수 있습니다. Hooks의 종류 중 하나인 useState를 먼저 배우겠습니다.

useState는 배열 비구조화 할당 문법과 같습니다. useState를 활용한 코드를 Say.js에 작성해봅시다.

<javascript />
// Say.js import { useState } from "react"; const Say = () => { const [message, setMessage] = useState(''); const onClickEnter = () => setMessage("안녕하세요!"); const onClickLeave = () => setMessage("안녕히가세요!"); return ( <div> <button onClick={onClickEnter}>입장</button> <button onClick={onClickLeave}>퇴장</button> <h1> {message} </h1> </div> ); }; export default Say;

 

  • useState 함수 인자에는 상태의 초깃값을 지정, 객체가 아니어도 괜찮음
  • 함수를 호출하면 배열이 반환
    *  배열의 첫 번째 원소는 현재 상태
    *  배열의 두 번째 원소는 상태를 바꾸어주는 함수,  setter 함수
<javascript />
// App.js import Say from "./Say"; const App = () => { return <Say /> } export default App;

4.4. 📚 한 컴포넌트에서 useState 여러 번 사용하기

<javascript />
// Say.js import { useState } from "react"; const Say = () => { const [message, setMessage] = useState(''); const onClickEnter = () => setMessage("안녕하세요!"); const onClickLeave = () => setMessage("안녕히가세요!"); const [color, setColor] = useState('black'); return ( <div> <button onClick={onClickEnter}>입장</button> <button onClick={onClickLeave}>퇴장</button> <h1 style = {{ color }}> {message} </h1> <button style={{ color: 'red'}} onClick={() => setColor('red')}> 빨간색 </button> <button style={{ color: 'green'}} onClick={() => setColor('green')}> 초록색 </button> <button style={{ color: 'blue'}} onClick={() => setColor('blue')}> 파란색 </button> </div> ); }; export default Say;

4.5. 📚 state 사용 시 주의 사항

  • state 값을 바꿀때는 setState 혹은 useState를 통해 전달받은 세터(setter) 함수를 사용
  • 배열이나 객체를 업데이트 할 때는 사본에 값을 업데이트하고 그 사본의 상태를 setState나 세터 함수로 업데이트
  • 사본은 spread 연산자를 사용하고 배열의 사본은 내장 함수를 활용

 

 

 

반응형
profile

다라다라V

@DaraDaraV

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!