끄적끄적 코딩
article thumbnail
Published 2023. 6. 20. 15:28
[React] 컴포넌트 React

컴포넌트의 기능은 단순한 템플릿 이상이다

- 데이터가 주어졌을 때 UI 생성
- 라이프사이클 API를 이용하여 컴포넌트가 화면에서 나타나거나 사라지는 등 변화가 나타날 때 주어진 작업을 처리
- 임의 메서드를 만들어 특별한 기능을 추가


클래스형 컴포넌트

import { Component } from 'react';

class App extends Component {
	// render 함수가 꼭 필요하다.
  render() {
    const name = 'react';
    return <div>{name}</div>
  }
}

export default App;

 

클래스형 컴포넌트와 함수 컴포넌트 차이

클래스형 컴포넌트

- 객체지향 프로그래밍 구조를 가지며, state를 초기화 하기 위해 constructor을 가진다.
- 코드가 길고 사이즈가 크다. (함수 컴포넌트에 비해)
- state 기능 및 라이프 사이클 기능을 사용할 수 있다.
- render 함수가 꼭 있어야 한다.

함수 컴포넌트

- Hooks를 사용하여 생성자 함수를 통해 state를 초기화 하지 않더라도 사용이 가능하다. (useState())
- 선언하기가 좀 더 편하고, 메모리 자원을 덜 사용한다.
- 제공되는 Hooks 함수뿐만 아니라 커스텀 훅을 만들 수 있다.
- state와 라이프사이클 API가 사용이 불가능하다. (⇒ v16.8 이후 Hooks로 해결)


* 리액트 공식 메뉴얼에서는 컴포넌트를 새로 작성할 때 함수 컴포넌트Hooks를 사용하도록 권장한다.
* 클래스 컴포넌트가 사라지는 것은 아니니, 클래스 컴포넌트의 기능은 꼭 알아두어야 한다.

 

 

 

props

정의

컴포넌트 속성을 설정할 때 사용하는 요소
props 값은 해당 컴포넌트를 호출하는 부모 컴포넌트에서 설정할 수 있다.

1. JSX 내부에서 props 렌더링

MyComponents 컴포넌트에서 props를 렌더링 하도록 수정하면 다음과 같다.

const MyComponent = (props) => { // 이때 props는 {'name': 넘겨준 값} 형태로 받아진다. 
	return <div>안녕하세요, 제 이름은 {props.name}입니다.</div> 
} 

export default MyComponent;

 

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

MyComponents를 호출하는 App.js에서 props를 지정할 수 있다.

import MyComponent from './MyComponent';

const App = () => {
	return <MyComponent name='이수화'/>;
};
 
export default App;


3. props 기본값 설정: defaultProps

이렇게 props를 직접 넘겨주지 않고, 컴포넌트 내에서 기본값을 설정하고 싶다.
⇒ defaultProps를 사용

import MyComponent from './MyComponent';

const App = () => {
	return <MyComponent/>; // name의 값을 지정 x
};
 
export default App;
const MyComponent = (props) => { 
	return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>
}

MyComponent.defaultProps = {
	name: '기본값'
}
 
export default MyComponent;

 

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

컴포넌트 태그 사이의 내용을 보여주고 싶다.
 children을 사용

  • 상위 컴포넌트 : App.js
import MyComponent from './MyComponent';

const App = () => {
	return <MyComponent>이수화</MyComponent>;
};
 
export default App;
  • 하위 컴포넌트 : MyComponent.js
const MyComponent = (props) => { 
	return <div>
		안녕하세요, 제 이름은 {props.name}입니다.
		children 값은 {props.chilren}입니다. 
	</div>
}

MyComponent.**defaultProps** = {
	name: '기본값'
}
 
export default MyComponent;

 

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

props 내부의 프로퍼티를 접근할 때 **props.**이 붙는게 불편하다.
 비구조화 할당으로 내부값을 바로 추출

const MyComponent = (props) => { 
	const {name, children} = props;

	return <div>
		안녕하세요, 제 이름은 {name}입니다.
		children 값은 {chilren}입니다. 
	</div>
}

MyComponent.**defaultProps** = {
	name: '기본값'
}
 
export default MyComponent;
  • 이렇게도 쓸 수 있다.
const MyComponent = ({name, children}) => { 

...

 

6. propTypes를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 props의 타입을 지정하고 싶다.
 propTypes 사용

import PropTypes from 'prop-types';

const MyComponent = (props) => { 
	const {name, children} = props;

	return <div>
		안녕하세요, 제 이름은 {name}입니다.
		children 값은 {chilren}입니다. 
	</div>
}

MyComponent.defaultProps = {
	name: '기본값'
}

MyComponent.**propTypes** = {
  name: PropTypes.string
};
 
export default MyComponent;

 

propTypes란

앱이 커짐에 따라 타입 검사를 활용하면 많은 버그를(bug) 잡을 수 있습니다. 특정 애플리케이션에서는 전체 애플리케이션의 타입 검사를 위해 Flow 또는 TypeScript와 같은 JavaScript 도구(Extensions)를 사용할 수 있습니다. 이러한 것들을 사용하지 않더라도 React는 내장된 타입 검사 기능들을 가지고 있습니다. 컴포넌트의 props에 타입 검사를 하려면 다음과 같이 특별한 프로퍼티인 propTypes를 선언할 수 있습니다.

isRequired 속성으로 type을 필수로 지정하도록 할 수 있다.

MyComponent.propTypes = {
  name: PropTypes.string,
	favoriteNumber: PropTypes.number.isRequired,
};

 

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

클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 된다.
그 외는 함수 컴포넌트와 유사하다.

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyComponent extends Component {
  static defaultProps = {
    name: '기본 이름',
  };
  static propTypes = {
    name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired,
  };
  render() {
    const { name, favoriteNumber, children } = this.props; // 비구조화 할당
    return (
      <div>
        안녕하세요, 제 이름은 {name} 입니다. <br />
        children 값은 {children}
        입니다.
        <br />
        제가 좋아하는 숫자는 {favoriteNumber}입니다.
      </div>
    );
  }
}

MyComponent.defaultProps = {
  name: '기본 이름'
};

MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired
};

export default MyComponent;

 

 

 

state

정의

- 컴포넌트 내부에서 쉽게 바뀔 수 있는 값

react는 총 2개의 state가 있다.

- 클래스형 컴포넌트가 지니고 있는 state
- 함수 컴포넌트에서 useState라는 함수를 통해 사용하는 state

클래스형 컴포넌트의 state

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0,
    fixedNumber: 0
  };
  render() {
    const { number, fixedNumber } = this.state; // state 를 조회 할 때에는 this.state 로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <h2>바뀌지 않는 값: {fixedNumber}</h2>
        <button
          // onClick 을 통하여 버튼이 클릭됐을 때 호출 할 함수를 지정합니다.
          onClick={() => {
            // this.setState(prevState => {
            //   return {
            //     number: prevState.number + 1
            //   };
            // });
            // // 위 코드와 아래 코드는 완전히 똑같은 기능을 하는 코드입니다.
            // // 아래 코드는 함수에서 바로 객체를 반환한다는 의미입니다.
            // this.setState(prevState => ({
            //   number: prevState.number + 1
            // }));
            this.setState(
              {
                number: number + 1
              },
              () => {
                console.log('방금 setState 가 호출되었습니다.');
                console.log(this.state);
              }
            );
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

 

 

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

react 16.8 이전 버전에서는 함수 컴포넌트에서 state를 사용할 수 없었지만, 16.8 이후 useState 함수를 사용하여 함수 컴포넌트에서도 state를 사용할 수 있게 되었다.

배열 비구조화 할당

const array = [1, 2];
const one = array[0];
const two = array[1]; 

// 비구조화 할당
const [one, two] = array;


useState 사용하기

  • 사용
const [message, setMessage] = useState(''); // 인자 : 상태의 초깃값 
// 반환 받는 값 : 현재 상태, 상태를 바꾸어주는 함수(세터 함수)  
  • 예제
import React, { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const onClickEnter = () => setMessage('안녕하세요!');
  const onClickLeave = () => setMessage('안녕히 가세요!');

  const [color, setColor] = useState('black'); // useState는 여러개 사용할 수 있다. 

  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;

 

state의 불변성

불변성 : 메모리 영역에서의 직접적인 변경을 하지 않고, 기존의 값을 수정하지 않으면서 새로운 값을 만들어내는 것

state가 불변성을 지켜야 하는 이유
기존의 state가 불변성을 지켜주어야 리액트 컴포넌트에서 상태가 업데이트 됐음을 감지할 수 있고, 이에 따라 필요한 리렌더링이 진행되기 때문


 

state를 사용할 때 주의 사항

state의 값을 바꿀때는 반드시 setState 혹은 useState를 통해 전달받은 세터함수를 사용해야 한다 !

배열이나 객체를 업데이트 해야할 때

- 배열이나 객체의 사본을 만들고, 그 사본에 값을 업데이트 한 후 setState 혹은 세터 함수를 통해 업데이트한다.
- 사본에 값을 업데이트 하는 예시

const object = {a: 1, b: 2, c: 3};
const nextObject = { ...object, b: 2 }; // 사본을 만들어서 b값만 덮어씀 (스프레드 연산자(js문법))

const array = [
	{ id: 1, value: true },
	{ id: 2, value: true },
	{ id: 3, value: false }
]

let nextArray = array.concat({ id: 4 }); // 배열에 새 항목 추가
nextArray.filter(item => item.id !== 2); // id가 2인 항목 제거
nextArray.map(item => item.id === 1 ? {...item, value: false} : item); // id가 1인 항목의 value를 false로 변경

'React' 카테고리의 다른 글

[React] ref란  (0) 2023.06.20
[React] 이벤트 핸들링  (0) 2023.06.20
[React] 리액트란  (0) 2023.06.20
[React] 리덕스 미들웨어  (0) 2023.05.30
[React] 리액트 라우터  (1) 2023.05.02

검색 태그