React Class형 컴포넌트로 만들어야 한다는 미션을 받았다.

헉 React를 class로요..?
그래, 사실은 React 도 class형 컴포넌트로 가득찬시기가 있었다. 하지만 React v16.8부터 React Hook 을 지원해주면서 공식문서에서도 함수형 컴포넌트와 함께 사용할 것을 권장했기 때문에 처음 React를 배울 때 이후로 함수형으로 구현 하던 나였는데...
대외적으로는 "함수형이 권장이니까~"라고 말하지만 사실은 Class로 컴포넌트 구현하는 법을 잊어버린 나 자신을 감추며 간단히 React 기반의 상품 필터링을 구현했다.
Class 컴포넌트를 사용하며 느꼈던점 Hook의 부재로 인한 상태관리 삽질을 정리해보았다.
import React, { Component } from 'react'
export default class RecentList extends Component {
render() {
return (
<div>
</div>
)
}
}
import React from 'react'
export default function RecentList() {
return (
<div>
</div>
)
}
로직과 상태를 컴포넌트 내에서 구현 = stateful
props 를 받아 this.props로 액세스 함componentDidMount,componentDidUpdate...)로직과 상태를 props로 받아 뿌려줌 = stateless
useState)useState: 상태 저장useEffect(callback,[]): 수명주기 동작 조정useEffect에서 callback을 트리거하여 componenetDidMount수명주기동작을 복제한다.comoponentWillUnMount 기능 수행
gif용량변화로 인해 영상이 깨지는점..양해바랍니다....
export default class RecentList extends Component {
state = {
recentFiltered: [],
brandList: [],
isUnlike: '',
};
//중략
| state | 설명 |
|---|---|
| recentProducts | localStorage에서 가져온 최근 상품항목 |
| recentFiltered | 필터링 될 때마다의 상품리스트 |
| brandList | 최근 상품 항목들의 브랜드 종류 리스트 |
각각의 필터를 클릭했을 시 클릭이벤트가 this.setState해 recentFiltered를 업데이트 하는 방식
setLowPriceOrder = () => {
const { recentFiltered } = this.state;
const lowOrderedList = recentFiltered.sort((a, b) => {});
this.setState({ recentFiltered: lowOrderedList });
};
setHighPriceOrder = () => {
const { recentFiltered } = this.state;
const highOrderedList = recentFiltered.sort((a, b) => {});
this.setState({ recentFiltered: highOrderedList });
};
setRecentViewOrder = () => {
this.setState({ recentFiltered: getStore('recentViewed')});
};
데이터 정규화가 안 된 상태
state는 서로의 state를 가지고 있으면 안되고 함수형 체이닝을 통해 재연산을 해야지 중복적으로 가지고 있으면 상태변경에 대한 추적이 어렵다.
함수형 체이닝이 아닌 함수 자체에서 각각 setState를 통해 상태를 변경하기 때문에 유지,보수와 상태변경 추적이 매.우 어렵다
실제로) 잦은 state변경으로 인해 변경하지도 않은 원본상품리스트가 변경되는 sideEffect 발생
중복된 state인 recentProducts를 제거하여 각 함수에서는 props로 해당 값을 받아서 사용하게 변경해야 한다.
현재 함수는 직접 state를 변경하지만 함수는 props(localStorage에서 가져온 최신상품리스트)를 이용해 필터링한 상품리스트만 return한다.
<개선 전>
render() {
const { recentFiltered } = this.state;
return (
{recentFiltered.map((product) => {
const { id } = product;
<개선 후>
render() {
const recentProducts = localSotrage.getItem(~
const viewdProducts = setHighPriceOrder(recentProducts)
return (
{viewdProducts.map((product) => {
const { id } = product;
즉 기존에는 다 필터링된 상품리스트를 this.state에서 가져와 렌더링했지만
localStorage에서 가져온 데이터를 메서드로 필터링한 후 바로 렌더링 하는 것이다.
즉 필터링한 리스트를 상태로 가지고 있을 필요없이 바로 렌더링 해주면 되는 방향으로 변경하는 것이다.
이로 인해 고통받으며 설계 시 고려해야 할 점을 정리해보았는데,
특히 this.state는 전역변수와 같은 존재인데, 모든 함수에서 이 state의 상태를 갱신하고 조작했다.
상태는 사용자의 입력에 따라 반응해야 하는데, Component 렌더링에 매우 의존적이게 되었고 이로 인해 추적 또한 어려워졌다.
2가지 상태(원본상품리스트, 필터링상품리스트)를 다 가지고 있었던 이유는 localSotrage에 계속적으로 접근하면 안좋다고 막연하게 생각해서였는데,
일단 localStorage는 성능상에 그렇게 큰 영향을 끼치지 않고 만약 성능상의 문제라면 component가 재렌더링에 더 초점을 둬야 한다는 결론은 얻었다.
localStorage에서 가져올 데이터는 사실상 실무에서는 서버에서 API 호출이다가져오는 것인데 실시간으로 최신상품을 보여줘야 하기 때문에 성능저하를 감수하더라도 매번 데이터를 가져오는 것이 필요하다는 것이 결론이다.
또 localStorage(=미래API요청)은 한곳에서 호출되면 네트워크 이슈 발생 시 추적이 편리하기 때문에 render에서 한번만 불러오는 것이 디버깅하기 쉽다.

상태관리 다음엔 제대로 해줄게.
현재 위코드와 프리온보딩 코스에 참여하고 있는데,
평소에 지나쳤던 기본적인 부분들을 다시금 체크하고,
또 그냥 뚝딱 만드는것에만 집중하지 않고 왜왜왜 했는지 조원분들이랑 공유하면서 많이 공부하고 있다.
모두 너무 감사합니다~~