[리액트를 다루는 기술] 3장 컴포넌트

정통파 개발자·2024년 12월 18일

리액트는 컴포넌트들의 집합이다.
개인적으로 컴포넌트를 잘 설계하여 랜더링을 최소화 시키고 재사용 하는것이 🌸리액트 기술의 꽃🌸이라고 생각한다!

컴포넌트를 만드는 두 가지 방법

리액트에서 컴포넌트를 생성하는 방법에는 두가지가 있다.
하나는 클래스를 통해, 하나는 함수를 통해 생성된다. 두 가지의 기능적 차이는 없지만 리액트에서는 함수형 컴포넌트를 권고한다. (힙 메모리 사용도 미세하지만 함수형이 더 적게 씀)

1. 클래스형

자바스크립트 ES6에서 클래스가 정식 도입되면서 리액트에서 클래스를 통해 컴포넌트를 생성할 수 있게 되었다.

기본 형태

import { Component } from 'react';

class MyComponent extends Component {
   constructor(props: any) {
    super(props);
    this.state = {
   		count: 1 
    }
  }
   
   render() {
   	 const state = this.state
     const props = this.props
   	 return <div>클래스 컴포넌트 형태</div>
   }
}

export default MyCompoent
  • constructor: 컴포넌트 생성자 super(props) 필수
  • render: JSX를 반환하여 화면을 그린다.
  • this: React Component 내 속성값들
{	
	props:{},
	context:{},
	refs:{},
	updater:{
    	enqueueForceUpdate: f,
        enqueueReplaceState: f,
        enqueueSetState: f,
        isMounted: f
    },
	state: {
    	count: 1
    },
	_reactInternals:{
		queue:[],
		replace:false
	}
}
  • props: 컴포넌트가 부모로부터 받은 속성값, 변경될때 리렌더링 된다.
  • context: React Context API를 사용할때 접근할 수 있는 contect
  • refs: 컴포넌트에서 선언한 refs, DOM 요소나 다른 컴포넌트의 인스턴스를 참조하는 객체
  • updater: 컴포넌트 상태를 업데이트하는데 사용되는 내부적인 객체, 상태 변경을 위한 비동기 큐 및 업데이트 메커니즘을 담당
  • state: 컴포넌트 내 관리하는 데이터들, 변경될때 리렌더링된다.
  • _reactInternals: 리액트 내부 구현에 관련된 정보, 직접 다룰 필요 없음.
    (예시에서 queue는 상태 업데이트 큐이며, replace는 상태가 교체되지 않고 업데이트 될 것임을 나타냅니다.
    이 객체는 React의 내부 최적화 및 리렌더링 관리에 사용됩니다.)

2. 함수형 (권고)

리액트 16.8 이상에서 Hooks가 나오면서 클래스형 컴포넌트의 모든 기능을 대체할 수 있게 되었다.

기본 형태

import React, { useState } from 'react';

const MyComponent = (props) => {
  const [count, setCount] = useState(0);
  return <div>함수형 컴포넌트 형태</div>;
};

export default MyComponent;
  • 함수형에서 this는 undefind
  • this.state 👉 useState()
  • this.props 👉 함수 컴포넌트의 인자
  • this.context 👉 useContext()
  • this.refs 👉 useRef()

Props & State

props

  • 컴포넌트 생성할때 참조되는 값으로 읽기 전용이다.
  • 부모에서 자식으로 전달하는 값이다.
  • prop 값을 변경하고 싶을땐 선언한 부모컴포넌트에서 변경해야한다.

state

  • 컴포넌트 내에서 스스로가 관리하는 값이다.
  • 마음대로 변경해도 됨, 단 React Hook의 setter 를 통해야한다.
  • 값은 원시형, 참조형, null 등 데이터 타입은 상관없이 선언 할 수 있으나, 참조형 데이터를 변경시 사본을 생성 기존 데이터를 엎어쳐 갈아끼운다.

Object: spread 연산자 사용

const [profile, setProfile] = useState({
	name: 'hope',
    age: 10,
   	address: '경기도'
})

// 주소만 변경하고 싶을때
const newProfile = {...profile, address: '경기도 수원시'}
setProfile(newProfile)

Array: spread 혹은 배열 함수 사용

const [productIds, setProductIds] = useState([1, 2, 3, 4, 5])

const addProductIds = productIds.concat(6)
const removeProductIds =productIds.filter((id) => id > 3)
const newProductIds = [...productIds]

참조형 데이터 타입의 state 변경 방법에는 한가지 공통점이 있다.
바로 새로운 주소값을 할당하는 것이다.
즉, 데이터 사본을 만든다 = 새로운 주소값을 할당

그럼 왜 기존의 할당된 데이터 자체를 수정하지 않고 새로 주소값을 할당하는 것일까?

1장에서도 다루었고 추후에 더 깊이 다루겠지만
리액트는 렌더링 전 가상돔과 값의 비교를 통해 변화를 감지한다고 했다.
만약 참조타입의 주소값이 아닌 데이터 값을 일일히 깊은 비교를 하게 된다면 연산의 비용이 크게 들것이고, 지금의 리액트와 같이 빠른 퍼포먼스는 기대하기 힘들것이다.

리액트는 얕은 비교를 통해 빠르게 데이터 변화를 감지하고 화면을 전환한다.
그렇기때문에, 참조형 데이터는 데이터의 사본을 통해 새로운 메모리 주소를 할당받아 변화를 감지하는 작업으로 동작된다.

이것이 바로 리액트에서 꼭 지켜야할 데이터의 불변성 특징(Immer)이다.

profile
🙋🏻‍♀️

0개의 댓글