React Hook의 어두운면


원문: Nir Yosef - The Ugly Side of React Hooks

필자는 이 글에서 React Hook에 대한 나의 관점에 대해 공유할 것이며, 이 글의 제목에서 알 수 있듯이 React Hook의 엄청난 팬은 아니다. 공식 React 문서에 설명된 대로 Hook 기반으로 작성된 클래스를 사용하지 않아야 하는 이유를 분석해 보겠다.

이유 #1: 클래스는 헷갈린다.

클래스가 React를 배우는 데 큰 장벽이 될 수 있음을 발견했다. 여러분은 이런 것들이 JavaScript에서 어떻게 작동하는지 방식을 이해해야 한다. 이는 대부분의 언어에서 작동하는 방식과는 매우 다르다. 또, 이벤트 핸들러를 바인딩하는 것도 기억해야 한다. 불안정한 구문 제안이 없으면 코드는 매우 장황해진다. […] React에서 함수와 클래스 컴포넌트의 차이와 각 컴포넌트를 사용하는 시기는, 숙련된 React 개발자 사이에서도 의견이 일치하지 않는다.

물론, 자바스크립트를 막 시작했을 때 this가 약간 혼란스러울 수 있다는 건 동의한다. 하지만 화살표 함수를 통해 그런 혼란을 해결할 수 있다. 그리고 TypeScript에 의해 이미 지원되는 3단계 기능을 "불안정한 구문 제안”은 순수한 선동론이다. React 팀은 이미 광범위하게 사용되고 있으며 곧 공식적으로 지원될 구문인 클래스 필드 구문을 언급하고 있습니다.

class Foo extends React.Component {
  onPress = () => {
    console.log(this.props.someProp);
  }

  render() {
    return <Button onPress={this.onPress} />
  }
}

보다시피 클래스 필드 화살표 함수를 사용하면 생성자 함수에서 아무것도 바인딩할 필요가 없으며, this는 항상 올바른 컨텍스트를 가리킨다.

클래스도 헷갈리는 상황에, 새로운 hook 함수는 어떨까? 일반 함수처럼 보이지만 hook 함수는 상태를 가지고 있고, 이상하게 보이는 this (aka useRef)와 여러 인스턴스를 가질 수 있다. 그러나 hook 함수는 클래스가 아니며, 함수와 클래스의 그 중간 어딘가에 있는 것이다. 이제부터는 그것을 Funclass라고 부를 것이다. 그렇다면 그 Funclass는 인간과 기계가 이해하기 더 쉬울까? 기계가 어떻게 받아들일지는 잘 모르겠지만, Funclass가 클래스보다 개념적으로 이해하기 쉽다고는 생각하지 않는다.

클래스는 잘 알려져 있고 확실한 개념이며, 모든 개발자가 이 개념에 익숙하다. 비록 자바스크립트에서는 조금 다르더라도 말이다. 반면에, Funclass는 새로운 개념이고 꽤 이상할 것이다. 이 개념은 훨씬 더 마법처럼 느껴지고, 엄격한 구문 대신 컨벤션에 너무 많이 의존한다. 엄격하고 이상한 규칙을 따라야 하고, 코드를 어디에 둘지 조심해야 하며, 많은 함정이 도사리고 있다. 누군가 Hook의 내부 메커니즘이 호출 순서를 기반으로 하므로, if 문 안에 hook을 넣지 말라고 말했다. 이건 정말 제정신이 아닌 것 같다! React와 같은 잘 알려진 라이브러리가 아니라, 반 조리된 POC 라이브러리에서 비슷한 것을 기대한다. useRef (this를 위한 멋진 이름), useEffect, useMemo, useImperativeHandle(뭐라고??) 등과 같은 끔찍한 이름에 대해서도 대비해야 한다.

클래스의 구문은 다중 인스턴스의 개념과 인스턴스 스코프의 개념(정확히는 this)을 처리하기 위해 특별히 고안되었다. Funclass는 잘못된 퍼즐 조각을 사용하여 동일한 목표를 달성하는 이상한 방법이다. 많은 사람이 Funclass를 함수형 프로그래밍과 혼동하고 있지만 Funclass는 실제로 클래스처럼 변장한 것일 뿐이다. 즉, 클래스는 구문이 아니라 개념이다.

참, 그리고 마지막 노트를 봐야 한다.

React에서 함수와 클래스 컴포넌트의 차이와 각 컴포넌트를 사용하는 시기는, 숙련된 React 개발자 사이에서도 의견이 일치하지 않는다.

지금까지, 컴포넌트 필요에 대한 구분은 매우 분명했다. 상태 또는 라이프 사이클 메서드가 필요하면 클래스를 사용했다. 그렇지 않다면, 함수 컴포넌트나 클래스 컴포넌트 어떤 것이든 상관없다. 필자는 함수 컴포넌트를 읽을 때, 이것이 상태가 없는 "멍청한 컴포넌트"라는 것을 즉시 알 수 있다는 생각이 개인적으로 좋았다. 하지만 슬프게도, Funclass의 도입으로 더는 이런 경우는 없을 것이다.

이유 #2: 컴포넌트의 상태와 연관된 로직을 재사용하기 어렵다.

React는 재사용 가능한 동작을 컴포넌트에 "붙이는" 방법을 제공하지 않는다(ex: 저장소(store)에 붙이기). React에는 상태 저장 로직을 공유하기 위한 더 나은 기본 요소가 필요하다.

아이러니하지 않은가? 필자는 React가 즉시 사용할 수 있는 상태 관리 솔루션을 제공하지 않아서, 우리가 이 빈 곳을 어떻게 메워야 하는지 매우 오랫동안 논쟁하게 했고, Redux 와 같은 매우 좋지 않은 디자인 패턴을 도입하도록 만들었다는 게 React의 가장 큰 문제라고 생각한다. 그래서 수년간의 좌절 끝에 React 팀은 마침내 컴포넌트 간에 상태 저장 논리를 공유하기 어렵다는 결론에 도달했다. 누가 예상했으랴.. 어쨌든, Hook이 상황을 더 좋게 만들 수 있을까? 답은 '아니다'라고 생각한다. Hook은 클래스와 함께 작동할 수 없으므로 코드베이스가 이미 클래스로 작성된 경우, 상태 저장 로직을 공유하기 위한 다른 방법이 필요하게 된다. 또한 Hook은 인스턴스별 로직 공유 문제만 해결하지만, 여러 인스턴스 사이에서 상태를 공유하려면 여전히 저장소 및 서드파티 상태 관리 솔루션을 사용해야 한다. 앞서 말했듯, 여러분이 이미 그런 것들을 사용하고 있다면 Hook은 정말로 필요 없게 된다. 따라서 React는 이런 증상을 해결하느라 진땀빼는 대신, 전역 상태 (저장소)와 로컬 상태 (인스턴스 당)을 모두 관리하기 위한 적절한 상태 관리 도구를 만들어서 이런 허점을 완전히 없애야 할 때라고 생각한다.

이유 #3: 복잡한 컴포넌트는 이해하기 어렵다.

간단한 컴포넌트로 시작했지만, 관리할 수 없을 만큼 엉망으로 성장한 상태 저장 로직 및 사이드 이펙트 컴포넌트를 유지 보수해야 하는 경우도 많을 것이다. 각 라이프사이클 메서드에는 종종 관련 없는 로직이 섞여 있다. […] 서로를 변경하는 코드들은 분리될 수 있지만, 전혀 관련이 없는 코드는 별도의 메서드로 결합한다. […] Hook을 사용하면 라이프 사이클 메서드를 기반으로 분할을 강제하는 대신, 관련 컴포넌트(예 : 구독 설정 또는 데이터 가져오기)에 따라 하나의 컴포넌트를 더 작은 함수로 분할할 수 있다.

여러분이 저장소를 사용하고 있다면, 이 인자들은 거의 관련이 없을 것이다. 다음 코드를 보자.

class Foo extends React.Component {
    componentDidMount() {
        doA(); 
        doB(); 
        doC();
    }
}

위 예제에서 볼 수 있듯이 componentDidMount에서 관련 없는 로직을 합칠 수 있지만, 컴포넌트가 더 커지고 있는가? 전혀 아니다. 전체 구현은 클래스 외부에 있고, 상태는 저장소에 있다. 저장소가 없으면 모든 상태 저장 로직이 클래스 내부에서 구현되어야 하며, 클래스의 덩치가 실제로 더 커졌을 것이다. 다시 말하지만, React는 상태 관리 도구가 없는 세상에 존재하는 대부분의 문제를 해결하는 것처럼 보인다. 하지만 실제로는, 대부분의 대형 앱은 이미 상태 관리 도구를 사용하고 있고, 앞서 말한 문제는 이미 완화된 상태다. 또한, 대부분의 경우 이 클래스를 더 작은 컴포넌트로 나누고 각 doSomething()을 하위 컴포넌트의 componentDidMount에 넣을 수 있다.

Funclasses를 사용하면 다음과 같이 작성할 수 있다.

function Foo() {
   useA(); 
   useB(); 
   useC();
}

이 코드는 좀 더 깔끔해 보이지만, 정말 그럴까? 여전히 어딘가에 3개의 서로 다른 useEffect Hook을 작성해야 하므로, 결국엔 더 많은 코드를 작성하게 될 것이다. 지금껏 무엇을 했는지 다시 돌이켜 보자. 클래스 컴포넌트를 사용하면, 컴포넌트가 마운트 단계에서 수행하는 작업을 한눈에 알 수 있다. Funclass 예제에서는, 컴포넌트가 마운트 단계에 수행하는 작업을 이해하기 위해서 각 Hook을 찾아가서 useEffect를 찾기 위해 비어있는 디펜던시 배열로 검색해 봐야 한다. 라이프사이클 메서드의 선언적 특성은 장점이 많으며, 필자는 Funclass의 코드 흐름을 조사하는 게 훨씬 더 어렵다고 생각한다. Funclasses로 인해 개발자가 실수로 잘못된 코드를 작성하는 경우가 많았다. 이것에 대해서는 나중에 예제를 살펴볼 것이다.

그러나, useEffect도 장점이 있음을 인정하겠다. 다음 예제를 보자.

useEffect(() => {
    subscribeToA();
    return () => {
      unsubscribeFromA();
    };
 }, []);

useEffect Hook을 사용하면, 구독 및 구독 취소 로직을 함께 사용할 수 있다. 이런 패턴은 정말 깔끔한 패턴이라고 생각한다. componentDidMountcomponentDidUpdate를 함께 사용하는 경우도 마찬가지다. 필자의 경험상 이런 경우는 흔하지는 않지만, 여전히 유효한 사용 사례이며 useEffect는 이 경우에 정말 유용하다. 하지만 여기서 문제는, useEffect를 사용하기 위해 반드시 Funclass를 사용해야 하는가?'이다. 클래스에서도 비슷한 것을 사용할 수 없을까? 그 대답은 '할 수 있다'다.

class Foo extends React.Component {
   someEffect = effect((value1, value2) => {
     subscribeToA(value1, value2);
     return () => {
        unsubscribeFromA();
     };
   })
   render(){ 
    this.someEffect(this.props.value1, this.state.value2);
    return <Text>Hello world</Text>   
   }
}

이펙트 함수는 주어진 함수를 메모하고, 매개 변수 중 하나가 변경된 경우에만 다시 호출된다. render 함수 내에서 이펙트를 트리거 하여, 매 렌더/업데이트가 수행될 때 호출되도록 할 수 있지만, 넘긴 함수는 매개 변수 중 하나가 변경된 경우에만 다시 실행되므로, componentDidMountcomponentDidUpdate를 결합한다는 측면에서는 useEffect의 유사한 결과를 얻는다고 할 수 있다. 하지만 안타깝게도, componentWillUnmount에서는 수동으로 마지막 정리를 수행해야 한다. 또한 render 내에서 이펙트 함수를 호출하는 것은 약간 못생겼다. useEffect와 똑같은 결과를 얻으려면 React는 이에 대한 지원을 추가해야 한다.

요점은, useEffect가 Funclass로 갈아타는 이유가 되어서는 안 된다는 것이다. 그것은 그 자체로 유효한 개념이며 클래스에도 구현될 수 있다.

링크에서 effect 함수를 확인할 수 있으며, 실제로 작동하는 모습은 작동 예제를 확인하면 된다.

이유 #4: 성능

우리는 클래스 컴포넌트가 의도치 않은 패턴을 통해 최적화 폴 백(fall back)의 더 느린 경로로 가게 한다는 것을 발견했다. 최신 도구에서도 클래스 사용 시 문제가 발생한다. 예를 들어, 클래스가 잘 minify 되지 않고, 핫 리 로딩이 불안정해진다.

React 팀은 클래스 코드를 최적화하고 최소화(minimize)하기 더 어렵고, Funclass는 어떻게든 개선이 되기는 한다고 말했다. 하지만 글쎄... 필자는 이렇게 말하고 싶다. 정확할 수치를 보여달라. Funclass vs 클래스의 성능을 비교하면서 지금까지 어떤 논문이나, 재현 할 수 있는 벤치마크 데모 앱을 찾을 수 없었다. 그런 데모를 보지 못했다는 사실 놀라운 일이 아니다. Funclass는 어떻게든 this(나 useRef)를 구현해야 한다. 따라서, 클래스를 최적화하기 어렵게 만드는 동일한 문제가 Funclass의 최적화에도 영향을 미칠 것으로 예상한다.

어쨌든, 성능에 대한 모든 논쟁은 수치를 보여주지 않는다면 아무 가치도 없다. 그래서 우리는 이 논쟁을 할 필요가 없다.

이유 #5: Funclass가 더 간결하다

Class를 Funclass로 변환해서 코드 줄이기에 대한 많은 예제를 찾을 수 있지만, 대부분의 예제는 componentDidMountcomponentWillUnmount를 결합하기 위해 useEffect Hook을 활용해서 큰 효과를 얻는다. 그러나 앞서 말했듯, useEffect는 Funclass의 장점으로 간주하여서는 안되며, 이로 인한 코드 감소를 무시하면 효과는 훨씬 줄어들게 된다. 그리고 useMemo, useCallback 등을 사용하여 Funclass를 최적화하려고 하면, 클래스보다 더 장황한 코드로 끝날 수도 있다. 작고 사소한 컴포넌트를 비교할 때는 Funclasses가 의심할 여지없이 승자가 된다. 클래스에는 클래스가 아무리 작더라도 지급해야 하는 고유한 상용구가 있기 때문이다. 그러나 큰 컴포넌트를 비교할 때는 둘 사이의 차이점을 거의 알 수 없으며, 때로는 클래스가 더 깔끔할 수도 있다. 마지막으로 useContext에 대해 몇 마디 하겠다. useContext는 우리가 현재 클래스에 있는 원래 컨텍스트 API에 비해 크게 개선되었다. 그러나 다시 말하지만, 클래스용으로 이 멋지고 깨끗한 API를 사용하지 않는 이유는 무엇인가? 어째서 사용하지 않는가?

// "./someContext"내부 :
export const someContext = React.Context({helloText: 'bla'});
// "Foo" 내부:
import {someContext} from './someContext';
class Foo extends React.component {
   render() {
      <View>
        <Text>{someContext.helloText}</Text>
      </View>
   }
}

helloText가 컨텍스트에서 변경되면, 변경 사항을 반영하기 위해 컴포넌트를 다시 렌더링해야 한다. 그게 다다. 못생긴 HOC 까지 필요하지도 않다. 그렇다면, React 팀이 일반 컨텍스트 API가 아닌 useContext API만 개선하기로 선택한 이유는 무엇일까? 필자는 그 이유를 잘 모르겠다. 하지만, 그게 Funclass가 본질적으로 더 깔끔하다는 의미는 아니다. 즉, React는 동일한 API 개선 사항을 클래스에도 구현해 주어야 한다.

그러니, 위 이유에 대해 몇 가지 질문을 한 뒤, Funclass가 마음에 들지 않는 다른 점들을 살펴볼 것이다.

숨어있는 사이드 이펙트

Funclass를 위한 useEffect 구현에서 필자를 가장 괴롭히는 것은, 주어진 컴포넌트의 사이드 이펙트가 무엇인지 명확히 알 수 없다는 것이다. 클래스를 사용하여 마운트 시 컴포넌트가 수행하는 작업을 확인하려면 componentDidMount에서 코드를 쉽게 확인할 수 있거나, 생성자 함수를 확인하면 된다. 반복되는 호출이 보이면 componentDidUpdate를 확인하면 된다. 새로운 useEffect Hook을 사용하면, 코드 내에서 사이드 이펙트가 깊숙이 숨겨질 수 있다.

원치 않는 서버 호출을 발견했다고 가정해 보자. 의심되는 컴포넌트의 코드를 보자.

const renderContacts = (props) => {
  const [contacts, loadMoreContacts] = useContacts(props.contactsIds);
  return (
    <SmartContactList contacts={contacts}/>
  )
}

별로 특별한 것은 없다. 과연 SmartContactList를 조사해야 할까, 아니면 useContacts에 대해 알아보아야 할까? 우선 useContacts를 자세히 살펴보겠다.

export const useContacts = (contactsIds) => {
  const {loadedContacts, loadingStatus}  = useContactsLoader();
  const {isRefreshing, handleSwipe} = useSwipeToReresh(loadingStatus);
  // ... useX() 함수들의 나열
  useEffect(() => {
    //** 엄청난 코드들, 연락처를 로딩하기 위한 애니메이션에 연관된 코드들이다.*//
  
  }, [loadingStatus]);
  
  //..나머지 코드들
}

자, 이제 조금 복잡해지기 시작했다. 숨어있는 사이드 이펙트는 어디 있을까? useSwipeToRefresh로 뛰어들면 볼 수 있을 것이다.

export const useSwipeToRefresh = (loadingStatus) => {
  // ..엄청난 코드들
  // ...
  
  useEffect(() => {
    if(loadingStatus === 'refresing') {
       refreshContacts(); // bingo! our hidden sideEffect!
    }  
  }); //<== 디펜던시 배열을 깜빡했다!
}

숨어있는 effect를 찾았다. refreshContacts는 모든 컴포넌트 렌더링에서 실수로 연락처 가져오기를 호출한다. 큰 코드 베이스와 일부 잘못 구조화된 컴포넌트에서 중첩된 useEffect는 심각한 문제를 일으킬 수 있다. 클래스로는 나쁜 코드를 작성하지 못한다는 말은 아니지만, Funclass는 훨씬 더 오류가 발생하기 쉬우며, 엄격하게 정의된 라이프 사이클 메서드 구조가 없어서 좋지 않은 코드를 작성하기 훨씬 쉽다.

늘어난 API

클래스와 함께 Hook API를 추가하면, React의 API가 거의 두 배가 된다. 모두 다 완전히 다른 두 가지 방법을 배워야 한다. 그리고, 필자는 새 API가 이전 API보다 훨씬 더 모호하다고 말하고 싶다. 이전 prop과 상태를 얻는 것과 같은 간단한 것들이 좋은 인터뷰 자료가 되고 있다. Google의 도움 없이 이전 prop을 얻기 위한 Hook을 작성할 수 있는가? React와 같은 큰 라이브러리는 API에 이런 큰 변경 사항을 추가하는 데 매우 주의해야 하며, 여기에서 얘기한 이유를 정당화할 수조차 없다.

부족한 선언성

필자의 생각으론 Funclass는 클래스보다 훨씬 더 지저분해지는 경향이 있다. 예를 들어, 컴포넌트의 진입점을 찾기가 더 어렵다. 클래스를 사용하면 render 함수만 검색하면 되지만, Funclass를 사용하면 메인 return 문을 찾기가 어려울 수 있다. 또한 코드를 어디서 찾을지 힌트를 제공하는 일반적인 라이프 사이클 메서드와 달리, 다른 useEffect 문을 따라서 컴포넌트의 흐름을 이해하는 것이 더 어렵다. 어떤 초기화 로직을 검색하는 경우(VSCode에서 cmd + shift + o), componentDidMount로 이동한다. 어떤 업데이트 메커니즘을 찾고 있다면, componentDidUpdate 등으로 넘어갈 것이다. 필자는 Funclass를 사용할 때 큰 구성 요소 내부에서 방향을 찾기 훨씬 더 어려웠다.

모두 React에 묶임

대부분의 개발자는, 간결한 논리로 만들어진 간단한 작업을 수행하기 위해 특정 React 라이브러리를 사용하고, 그런 코드들을 React에서 쉽게 분리 할 수 있다. react-use라는 라이브러리에서 가져온 위치 추적 Hook을 살펴보자.

import {useLocation} from 'react-use';
const Demo = () => {
  const state = useLocation();
  
  return (
    <div>
      {JSON.stringify(state)}
    </div>
  );
};

하지만, 다음 예제처럼 순수 바닐라 스크립트 라이브러리를 사용하는 게 더 낫지 않을까?

import {tracker} from 'someVanillaJsTracker';

const Demo = () => {
  const [location, setLocation] = useState({});

  useEffect(() => {
     tracker.onChange(setLocation);
  }, []);

  return (
    <div>
      {JSON.stringify(state)}
    </div>
  );
};

아래 예제가 더 장황해 보이는가? 그렇다. 첫 번째 해결책이 확실히 더 짧다. 그러나 두 번째 해결책은, JS 세계를 React와 분리된 상태로 유지하게 해주고, 몇 줄의 코드가 추가되는 것은 이런 중요한 일을 위해 지불하는 작은 비용이다. 커스텀 Hook은 순수한 로직을 React의 상태에 결합할 수 있는 무한한 가능성의 문을 열었으며, 이런 라이브러리는 산불처럼 널리 퍼지고 있다.

뭔가 잘못된 느낌

뭔가 옳지 않다는 느낌을 받아봤는가? 이것이 내가 Funclass를 보고 느끼는 느낌이다. 때로는 정확한 문제를 가리킬 수 있지만, 때로는 우리가 잘못된 길을 가고 있다는 일반적인 느낌만 받기도 한다. 좋은 개념을 발견 했을 때는, 그냥 그것이 멋지게 작동하는 것을 이해할 수 있다. 그러나, 잘못된 개념으로 어려움을 겪고 있을 때는 작업을 수행하기 위해 점점 더 구체적인 내용과 규칙을 추가해야 한다. Hook을 사용하면 이상한 것들이 튀어나온다. 사소한 작업을 수행하기 위한 "유용한" Hook들이 필요하다. 그리고 배워야 하는 더 많은 것들이 있다. 우리가 일상적인 작업을 하기 위해 너무 많은 유틸리티가 필요해지고, 그것들이 이상한 복잡함을 감추기 위한 것이라면, 우리가 잘못된 길을 걷는다는 중대한 신호임을 명심하자. 몇 년 전, Angular 1.5에서 React로 전환했을 때 React의 API가 얼마나 단순하고 문서가 얼마나 얇은지에 놀랐다. Angular는 거대한 문서를 가지고 있었다. 다이제스트 메커니즘, 다양한 컴파일 단계, transclude, 바인딩, 템플릿 등 모든 것을 다루려면 며칠이 걸렸을 것이다. 이 자체만으로도 뭔가 잘못되었다는 신호였다. 반면에, React는 본 즉시 옳다고 느꼈다. 깨끗하고 간결했으며, 몇 시간 만에 전체 문서를 살펴볼 수 있었다. 필자는 처음으로 Hook을 사용해보려고 할 때도, 두 번째 시도에도, 그리고 이후 계속해서 Hook 문서로 돌아가서 확인해야 할 의무(역: 필요)가 있음을 느끼게 되었다.


중요 사항

댓글 몇 개를 읽은 후, 많은 사람들이 내가 클래스 옹호자라고 생각한다는 것을 알았다. 음, 그건 사실과는 거리가 멀다. 클래스에는 많은 단점이 있지만 Funclass는 최악이다. 이 글의 시작 부분에서 이미 언급했듯이, 클래스는 구문이 아니라 개념이다. 클래스와 동일한 목표를 달성했지만, 가장 어색한 방식으로 그 목표를 달성한 끔찍한 프로토 타입 구문을 기억하는가? 필자는 그 느낌을 Funclass에서 느낀다. 이전 프로토 타입 구문을 싫어하려고 클래스를 좋아할 필요는 없고, Funclass를 싫어하기 위해 클래스를 좋아할 필요도 없다.) Funclass는 함수형 프로그래밍과 아무 관련이 없기 때문에, OOP와 함수형 프로그래밍 사이의 싸움도 아니다. 그리고 엄밀히 말하자면, React로 앱을 작성하는 것은 클래스를 사용하든 사용하지 않든 OOP가 아니다.

결론

필자는 흥을 깨고 싶지는 않지만(원문: I hate being the party pooper), Funclass는 React 커뮤니티에서 두 번째로 최악의 일이 될 수 있다고 생각한다(1위는 여전히 Redux 이다). 이미 취약한 생태계에 또 다른 쓸모없는 토론을 추가했다. Funclass가 권장되는 방법인지 아니면 다른 기능과 개인적인 취향의 문제인지는 확실하지 않다. 필자는 React 커뮤니티가 정신을 차리고 Funclass와 클래스의 기능 사이의 동등함을 요청하기를 바란다. 우리는 클래스에 더 나은 Context API를 가질 수 있고, 클래스 코드에 useEffect, 심지어 useState와 같은 것을 가질 수 있다. React는 우리가 원한다면 클래스를 계속 사용할 수 있는 선택권을 주어야 한다고 생각한다. 그리고 클래스를 남겨두고 Funclass에만 더 많은 기능을 추가한 채로 강제로 지원을 종료하지 않아야 한다. 그나저나, 2017년 말에 필자는“The ugly side of Redux”라는 제목의 글을 올렸다. 이제 Redux를 만든 Dan Abramov조차 Redux가 큰 실수라고 이미 인정했다. Image for post

https://mobile.twitter.com/dan_abramov/status/1191495127358935040

과연 이번에도 역사는 반복될까? 시간이 답일 것이다. 어쨌든 필자와 팀원들은 지금은 클래스를 계속 사용하기로 했고, Mobx 기반 솔루션을 상태 관리 도구로 사용하기로 했다. 필자는 홀로 일하는 개발자와 팀에서 일하는 개발자 사이에 Hooks의 선호도에 큰 차이가 있을 거라고 생각한다. Hooks의 나쁜 면은 다른 사람의 코드를 처리해야 하는 큰 코드 베이스에서 훨씬 더 잘 보일 것이다. 개인적으로 필자는 React가 모든 Hook을 ctrl + z 할 수 있었으면 좋겠다. 필자는 React를 위한 간단하고 깔끔한 내장 상태 관리 솔루션을 제안하는 RFC 작업을 시작할 예정이다. 이 솔루션은 상태 저장 로직을 공유하는 문제를 완전히 해결하고 Funclass보다 덜 어색한 방법으로 해결할 것이다. Image for post

박정환2020.09.22
Back to list