WIL 4 ( Weeked I Learned ) - 22/06/05

용스·2022년 6월 5일
0

WIL

목록 보기
4/15

React는 크게 클래스형 컴포넌트와 함수형 컴포넌트로 나뉘어 있다.

클래스형 컴포넌트

작성 방법

import React, { Component } from "react";

class App extends Component {
  render() {
    return <div>Hi</div>
  }
}

클래스형 컴포넌트에서는 render()를 이용하여 JSX 코드를 반환해준다.

특히, 클래스형 컴포넌트에서는 라이프 사이클을 관리할 수 있는 함수가 있다.

라이프 사이클이란?
컴포넌트가 생성되고 소멸될 때까지 컴포넌트의 생명 주기라고 이해하면 쉽다.

< 16.4 버전 이후의 생명 주기 - 참고 링크 >

라이프 사이클은 크게 나누면 3가지 단계로 이루어 진다.

Mount 될 때( 생성될 때 )
componentDidMount()

Update 될 때( 수정될 때, Re-rendering이라고도 한다. )
componentDidUpdate()

Unmount 될 때 ( 소멸될 때, Mount가 해제될 때 )
componentWillUnmount()

그리고 컴포넌트가 Update 될 경우는 다음 4가지 경우이다.

  • props : 부모 컴포넌트에서 받은 데이터가 업데이트 될 때
  • state : 자신의 컴포넌트 데이터가 변경될 때
  • 부모 컴포넌트가 업데이트 됐을 때
  • force-update : 강제로 업데이트 했을 때

이렇듯 클래스형 컴포넌트에서는 라이프 사이클 주기에 맞추어 이벤트를 추가하거나 state를 변경해야 했다. 하지만 함수형 컴포넌트에서는 더욱 간결하게 사용할 수 있다.

함수형 컴포넌트

작성 방법

import Recat from "react";

const App = () => {
  return <div>Hi</div>
}

클래스형 컴포넌트보다 코드가 훨씬 간결해졌으며, React Hook을 사용하여 컴포넌트의 state를 update 할 수 있다.
특히 클래스형 컴포넌트는 라이프 사이클에 맞지 않게 코드를 작성시, 의도치 않은 문제가 발생할 수 있다. 이로 인해 함수형 컴포넌트가 생겨나게 되었다.

React Hooks

Hook은 React 16.8버전부터 새로 추가된 요소이다. 클래스 바탕의 코드를 작성할 필요 없이 state 값과 여러 React 기능을 사용할 수 있도록 도와준다.

React hooks가 생겨나게 된 이유는 3가지로 정리할 수 있다.

1. 컴포넌트 사이의 상태 로직 재활용의 어려움
2. 컴포넌트의 복잡성 증가
3. this 사용성의 어려움

다음은 React 공식 사이트에서 함수형 컴포넌트의 장점에 대해 게시한 글이다.

1. 컴포넌트 사이에서 상태 로직을 재사용하기 어렵습니다.

React는 컴포넌트간에 재사용 가능한 로직을 붙이는 방법을 제공하지 않습니다. (예를 들어, 스토어에 연결하는 것) 이전부터 React를 사용해왔다면, render props이나 고차 컴포넌트와 같은 패턴을 통해 이러한 문제를 해결하는 방법에 익숙할 것입니다. 그러나 이런 패턴의 사용은 컴포넌트의 재구성을 강요하며, 코드의 추적을 어렵게 만듭니다. React 개발자 도구에서 React 애플리케이션을 본다면, providers, consumers, 고차 컴포넌트, render props 그리고 다른 추상화에 대한 레이어로 둘러싸인 “래퍼 지옥(wrapper hell)“을 볼 가능성이 높습니다. 개발자 도구에서 걸러낼 수 있지만, 이 문제의 요점은 심층적이었습니다. React는 상태 관련 로직을 공유하기 위해 좀 더 좋은 기초 요소가 필요했습니다.

Hook을 사용하면 컴포넌트로부터 상태 관련 로직을 추상화할 수 있습니다. 이를 이용해 독립적인 테스트와 재사용이 가능합니다. Hook은 계층의 변화 없이 상태 관련 로직을 재사용할 수 있도록 도와줍니다. 이것은 많은 컴포넌트 혹은 커뮤니티 사이에서 Hook을 공유하기 쉽게 만들어줍니다.

2. 복잡한 컴포넌트들은 이해하기 어렵습니다.

우리는 때론 간단하게 시작했지만 관리하기가 힘들어지는 상태 관련 로직들과 사이드 이펙트가 있는 컴포넌트들을 유지보수해야 합니다. 각 생명주기 메서드에는 자주 관련 없는 로직이 섞여들어가고는 합니다. 예시로 componentDidMount 와 componentDidUpdate는 컴포넌트안에서 데이터를 가져오는 작업을 수행할 때 사용 되어야 하지만, 같은 componentDidMount에서 이벤트 리스너를 설정하는 것과 같은 관계없는 로직이 포함되기도 하며, componentWillUnmount에서 cleanup 로직을 수행하기도 합니다. 함께 변경되는 상호 관련 코드는 분리되지만 이와 연관 없는 코드들은 단일 메서드로 결합합니다. 이로 인해 버그가 쉽게 발생하고 무결성을 너무나 쉽게 해칩니다.

위와 같은 예시에서, 상태 관련 로직은 한 공간안에 묶여 있기 때문에 이런 컴포넌트들을 작게 분리하는 것은 불가능하며 테스트하기도 어렵습니다. 이 때문에 많은 사용자들은 React를 별도의 상태 관리 라이브러리와 함께 결합해서 사용해왔습니다. 그러나, 이런 상태 관리 라이브러리는 종종 너무 많은 추상화를 하고, 서로 다른 파일들 사이에서 건너뛰기를 요구하며 컴포넌트 재사용을 더욱더 어렵게 만들었습니다.

이같은 문제를 해결하기위해, 생명주기 메서드를 기반으로 쪼개는 것 보다는, Hook을 통해 서로 비슷한 것을 하는 작은 함수의 묶음으로 컴포넌트를 나누는 방법을 사용할 수 있습니다. (구독 설정 및 데이터를 불러오는 것과 같은 로직) 또한 이러한 로직의 추적을 쉽게 할 수 있도록 리듀서를 활용해 컴포넌트의 지역 상태 값을 관리하도록 할 수 있습니다.

3. Class은 사람과 기계를 혼동시킵니다.

React 에서의 Class 사용을 위해서는 JavaScript의 this 키워드가 어떻게 작동하는지 알아야만 합니다. JavaScript의 this키워드는 대부분의 다른 언어에서와는 다르게 작동함으로 사용자에게 큰 혼란을 주었으며, 코드의 재사용성과 구성을 매우 어렵게 만들고는 했습니다. 또한 class의 사용을 위해 이벤트 핸들러가 등록되는 방법을 정확히 파악해야 했으며, 이는 불안정한 문법 제안들의 도움이 없을 시엔, 코드를 매우 장황하게 만들었습니다. 사용자들은 props, state, 그리고 top-down 데이터 흐름을 완벽하게 하고도, Class의 이해에는 어려움을 겪고는 했습니다. React 내의 함수와 Class 컴포넌트의 구별, 각 요소의 사용 타이밍 등은 숙련된 React 개발자 사이에서도 의견이 일치하지 않습니다.

React는 지난 5년 동안 널리 사용되어 왔으며, React의 개발진은 5년 뒤에도 React가 지금과 같이 널리 이용되길 원합니다. Svelte, Angular, Glimmer 등에서 보여주듯이, 컴포넌트를 미리 컴파일해놓는 방식에는 높은 잠재력이 있습니다. 템플릿에 한정하지 않는다면 더 그렇고요. 개발진은 최근 Prepack을 사용한 컴포넌트 folding에 대해서 실험해왔고 긍정적인 결과를 보았습니만, Class 컴포넌트가 이러한 최적화를 더 느린 경로로 되돌리는 의도하지 않은 패턴을 장려할 수 있다는 것을 발견했습니다. Class는 최근 사용되는 도구에서도 많은 문제를 일으킵니다. 예를 들어 Class는 코드의 최소화를 힘들게 만들고, 핫 리로딩을 깨지기 쉽고 신뢰할 수 없게 만듭니다. 우리는 코드가 최적화 가능한 경로에서 유지될 가능성이 더 높은 API를 제공하길 원하였습니다.

이러한 문제를 해결하기 위해, Hook은 Class없이 React 기능들을 사용하는 방법을 제시합니다. 개념적으로 React 컴포넌트는 항상 함수에 더 가깝습니다. Hook은 React의 정신을 희생하지 않고 함수의 사용을 권장합니다. Hook은 명령형 코드로 해결책을 찾을 수 있게 해주며 복잡한 함수형 또는 반응형 프로그래밍 기술을 배우도록 요구하지 않습니다.

다음은 내가 사용해본 React hook 들이다.

useState

state의 불변성을 위해 useState로 state 값을 수정할 수 있다.

import React from "react"

const CustomComponent = () => {
  // value : state, setValue : state를 관리할 함수 
  // useState( value ) : value는 state의 초기값
  const [ value, setValue ] = React.useState(0);
  
  const updateValue = () => {
    // value = value + 1; 이런 식으로는 state를 변경할 수 없다.
    // state의 불변성을 유지하기 위해서이다.
    setValue( value + 1 );
  }
}

useEffect

import React from "react";

const CustomComponent = () => {
  useEffect(() => {
    // 컴포넌트가 Mount 및 Update 될 때 실행된다.
    console.log('컴포넌트가 화면에 나타남');
    return () => {
    // 컴포넌트 Unmount 때 실행된다
    // clean up 이라고도 한다.
      console.log('컴포넌트가 화면에서 사라짐');
    };
  }, []);
}

아직은 React hooks를 많이 다뤄보지 않았으나, 점차 개발 경험이 많아지면 다양한 hook들을 사용하게 될 것 같다.

향후 전망은?

React 공식 사이트에서는 클래스형 컴포넌트를 제거할 계획은 없다고 밝혔다. 하지만 관리가 쉽고 오류를 덜 발생할 수 있는 함수형 컴포넌트가 더욱 많이 쓰이지 않을까? ( 또한, 점진적이라고 표현하니 점차 사라질 수도 있을 것 같다. )

profile
일단 해보자

0개의 댓글