리액트는 컴포넌트들의 집합이다.
개인적으로 컴포넌트를 잘 설계하여 랜더링을 최소화 시키고 재사용 하는것이 🌸리액트 기술의 꽃🌸이라고 생각한다!
리액트에서 컴포넌트를 생성하는 방법에는 두가지가 있다.
하나는 클래스를 통해, 하나는 함수를 통해 생성된다. 두 가지의 기능적 차이는 없지만 리액트에서는 함수형 컴포넌트를 권고한다. (힙 메모리 사용도 미세하지만 함수형이 더 적게 씀)
자바스크립트 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
super(props) 필수{
props:{},
context:{},
refs:{},
updater:{
enqueueForceUpdate: f,
enqueueReplaceState: f,
enqueueSetState: f,
isMounted: f
},
state: {
count: 1
},
_reactInternals:{
queue:[],
replace:false
}
}
리액트 16.8 이상에서 Hooks가 나오면서 클래스형 컴포넌트의 모든 기능을 대체할 수 있게 되었다.
import React, { useState } from 'react';
const MyComponent = (props) => {
const [count, setCount] = useState(0);
return <div>함수형 컴포넌트 형태</div>;
};
export default MyComponent;
undefindconst [profile, setProfile] = useState({
name: 'hope',
age: 10,
address: '경기도'
})
// 주소만 변경하고 싶을때
const newProfile = {...profile, address: '경기도 수원시'}
setProfile(newProfile)
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)이다.