JIGGAG

9월 한달동안 로그

2022년 9월 30일

9/26 ~ 9/30

useEvent

  • RFC: useEvent
  • useEffect나 useCallback에서 디펜던시로 추가하고 싶지는 않지만 사용해야하는 경우 ref로 조건 처리하고는 했는데
  • 이런 상태를 대체할 수 있을 것이라 보고 있었으나
  • 뒤돌아서 생각해보면 디펜던시 대혼란에 빠지게 될 것 같았다
  • 린트 룰을 꺼버리는게 차라리 나을지도 모르는? (이게 더 명시적이니깐)
  • 근데 useEvent가 대혼란을 극복하지 못하고 사라지는중

default export

  • [번역] 자바스크립트 모듈에서 default export는 끔찍합니다
  • default export는 어떤 이름으로든 export 할 수 있으므로 여러 개발자는 default import를 위해 각각 다른 이름과 명명 스키마를 생각할 것입니다
  • 만약 다른 모듈에서 명명된 두 named export의 이름이 같은 경우 어떻게 해야하나요?"라고 생각할 수 있습니다. 다행히 이 문제는 import aliasing으로 쉽게 해결할 수 있습니다.
    • 그러나 import 할 때마다 이름을 고민하는 것 보다 하나의 파일 안의 스코프에서 일회성으로 이름을 고민하는 것이 훨씬 편합니다.
    • default export로 매번 import 할때마다 고민하기보다 동일한 이름의 named export가 발생한 시점에 일회성으로 고민하는 것이 더 낫다
  • 그럼에도 default export 를 써야겠다면?
    • index 파일을 만들어서 여기에 전부 default import 하고 이 index 에 접근하도록

{}

9/19 ~ 9/25

flex 레이아웃

  • 항상 잘 사용하지 못하는 flex
  • 이 글 여러번 읽었더니 드디어 이해가...
    • 감성으로 이해하는데, 이제 이성으로도 살짝!
    • 두번 정도 더 겪으면 될 것 같다
  • 하지마 알고 있고 이해하는 것과 다르게 제대로 사용하는 것
    • 제대로 사용하는 것까지 이어져야 완전히 내것이 되는데
    • 가장 조심해야하는 것이 무의식적인 사용
  • 지금도 잘 사용하고 있다고 생각하는 것이 있다면....
    • 나혼자만의 착각

데드라인 드리블 글쓰기

  • 데드라인 드리블 글쓰기
  • 한달에 하나 정도 더 쓰자는 마음이였는데 실행하지 못한지 반년 훌쩍
  • 나 또한 마찬가지로 한달동안을 마지노선으로 가져간다...
  • 글감을 바로 메모해두며 그것이 글이 되어야하는데, 내 글감은 그대로 한마디가 되고 끝나버린다
  • 짧은 생명주기

스터디를 진행하고 나면

  • 책을 한권 읽는다던지 그리고 후기를 적는다면
  • 이런느낌으로 정리해두는 것도 좋겠는데
  • 스터디를 참여하는 것 자체가 부담이라면
  • 이런 온라인에 올라와있는 후기와 함께 개인적으로 느낀 것을 정리하면서 읽어보는 것도 재밋겠다
  • 단위테스트 책을 읽어보고 싶었는데, 후기에 올라온 내용처럼 보통 백엔드 위주의 내용이라 어떻게 접목할 수 있을까 하는 고민이였다

타입스크립트 프로젝트 클린 아키텍처 (의존성 분리)

  • (번역)타입스크립트 프로젝트를 위한 궁극적인 클린 아키텍처 템플릿
  • 예제는 core, data, di, presenter 구성인데, RN 플젝을 이렇게 구성한다면?
    • presenter에 일반적인 components, container
    • core에서는 presenter에서 사용할 유즈케이스
    • data에 core의 유즈케이스에서 사용할 데이터 구조
    • di에서 data를 core의 유즈케이스에 따라 변환하여 실제 presenter에서 사용
  • 패키지 간의 종속성 설정에서 이런 의존성을 확인할 수 있다
    • data는 core에 의존
    • di는 data, core에 의존
    • presenter는 di, core에 의존
  • 이런 의존 관계로 인해 core가 변경되면 data, di, presetner 모두 다시 빌드 되어야한다
    • data가 달라지면 core에서 처리하는 과정이 변경되어야하고 이에 따라 di도 달라질 수 있다
    • di가 변경되면 core에서 data를 변환하는 과정이 달라져야하고
    • core가 변경되면 data를 변환한 di가 달라지고 presenter에서 보여지는 것이 달라질 수 있기 때문
  • 확실하게 의존성 분리가 되겠는데, 갑자기 리덕스가 생각난다 🤔

9/12 ~ 9/18

프론트엔드 아키텍쳐

  • 프론트엔드 아키텍쳐 트랜드?
    • redux + saga가 원탑이라고 생각하던 지난 시간
    • 지금은 서버 API 캐싱을 잘 관리하는 것이 더 중요해졌다
    • 이렇게 계속 변화되는 아키텍쳐 속에서 하고자 하는 의미만 알아두면 좋겠다
  • 비즈니스 로직을 완전히 분리하여 View를 구성할 수 있다면 좋겠지만
    • 분리하지 못한다면 비즈니스 로직을 포함한 거대한 컴포넌트가 되어버리는데
      • 로직도 있고 View도 있고
  • 여기서 View만 이라도 한번 더 분리해서 UI 독립적일 수 있게 되면 좋겠지만
    • 그럼 props drilling하게 되고 오히려 컴포넌트가 어디서든 재사용하는 것이 어려운
    • UI 독립이기는 하지만 정말 독립적이지는 않은 이 로직에 대하여 의존적인 컴포넌트가 되었다
  • 어차피 재사용 되지 못한다면 비즈니스 로직에 의존적이더라도 언제든 다른 것으로 교체가능하도록
    • 재사용은 되지 않지만 교체는 수월한 최소한의 컴포넌트

선언형, 명령형 관계

  • 선언형, 명령형 코드 그리고 추상화
    • 명령형 => 어떻게(How)
      const 등록완료된_리스트 = (list) => {
      	const result = [];
      	for (let i = 0; i < list.length; i++) {
      		if (list[i].isCompleted) {
      		  result.push(list[i])
      		}
      	}
      
      	return result;
      };
      
    • 선언형 => 무엇을(What) => 명령형에서 어떻게(How)를 감추고 무엇을(What)만 노출 => 명령형을 추상화하였다
      const 등록완료된_리스트 = (list) => {
      	return list.filter(item => item.isCompleted);
      };
      
    • 선언형 내부에 명령형이 추상화되어 숨겨져있다
  • 그렇다면 명령형 선언형 구분할 필요 없이 명령형을 구조적으로 정리하여 내부에 숨겨두는 것이 무조건 선언형인가?
    • 선언형은 사이드 이펙 없이 순수해야한다 라는 내용에 따르면 언제 어디서 + 어떤 상황에서 호출되어도 동일한 기댓값을 주어야한다
    • 명령형 => 시간 순서를 지켜야하는 절차적으로 호출
    • 선언형 => 순수하기 때문에 시간 순서 상관없이 어디서든 호출
  • 모든것을 선언형으로만 작성할 수 없을 것 같다
    • 선언형 내부를 따라가다보면 결국 시간 순서에 따라 작성되어있는 명령형이 감춰져있을 것
    • 이것들을 추상화하여 잘 전달하고 사용하도록
  • 그럼 이런 명령형 코드를 찾아보게 되는 시점이 언제 있을까?
    • 추상화되어있는 RN 컴포넌트나 브릿지 사용하다가 무언가 오잉? 하는 시점에 따라가다보면
    • 어디엔가 나열되어있는 명령형 코드를 찾아볼 수 있다
  • 이 글을 읽고 하나 더 와닿은
    • 회사 프론트 동료들과 추상화와 선언적인 코드의 관계에 대해서 이런저런 이야기를 나눴습니다. 머릿속에 추상적으로 있던 개념이 좀 각이 잡혀서 ㅎㅎ 한 번 글로 적어보려 합니다.
    • 이야기 한 것 만으로 머릿속에서 정리하고 흘러갈 수 있는 것을 기록하면서 다시 한번 다듬어서 남겨두기

9/5 ~ 9/11

리액트 베타 문서

리액트 컴포넌트 리렌더링

RN fabric

  • 아직도 안드로이드 fabric 버전에서 ReactNavigation 라이브러리가 동작하지 않는다
  • 이것저것 확인해보니 디펜던시 라이브러리가 문제가 되고 있는 듯 (react-native-screens, react-native-safe-area-context 무언가)
  • ndk 오류 관련 깃헙 이슈 코멘트
    • 최근에 RN 0.70.0 에서도 cmake로 변경되었던데....?
    • 혹시나 해보면 RN 버전부터 다시 올려본다 => 그러나 safe-area-context가 아직 대응이 되지 않았기에 여전했다...
  • 같은 이슈가 올라와있는데 아직....
  • 근데 전부터 FabricExample 살펴보면 항상 의문인 것은 newArchEnabled=false?
    • fabric 버전으로 올린 이유가 이거 때문 아닌가..?
  • ☠️ 대체 왜...

리액트 상태 관리

  • [번역] 리액트 상태 관리의 새로운 흐름
  • 리액트에서는 전역으로 상태를 관리하는 방법에 대한 가이드라인이 없다
    • 단순히 전역으로 전달하는 것은 Context로 할 수 있지만
    • 여기서 말하는 상태 관리와는 목적이 다르다
    • 참고: 전역상태 관리에 대한 단상 - Context API 성능
    • 전역 상태 관리에 대한 최적화 처리가 되어있는 Redux와 달리 Context는 전달하는 목적만 있었기에 최적화 작업이 포함되어있지 않다
    • 그렇다면 Context를 활용해 전역에서 접근한다면 어떻게 될까?
    • 사용하는 곳에서 단순한 Context 변경사항에도 리렌더를 유발하게 된다
      •   Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop가 바뀔 때마다 다시 렌더링 됩니다
          .
          상위 컴포넌트에서 React.memo 또는 shouldComponentUpdate를 사용하더라도 useContext를 사용하고 있는 컴포넌트 자체에서부터 다시 렌더링됩니다.
          .
          useContext를 호출한 컴포넌트는 context 값이 변경되면 항상 리렌더링 될 것입니다.
        
      • 문서: useContext
      • 컨텍스트 잘 사용하기: 메모이제이션 최적화
        • 컨텍스트 분리 또는 하위 컴포넌트 memo 또는 useMemo로 jsx 반환
    • 하위 컴포넌트에서 최적화를 진행하더라도 결국 불필요한 리소스가 소요된다
  • 각각의 라이브러리들은 서로 다른 문제에 대해 서로 다른 해결방법을 제시했는데
    • 요구사항에 맞는 적절한 라이브러리를 선택할 수 있어야한다
  • 전역 상태 관리 라이브러리가 해결하고자 하는 문제
    • 저장된 상태를 컴포넌트 트리 어디에서든지 읽어 올 수 있는 기능
      • props drilling을 피하고 어디서든 이 상태를 가져와서 사용하고자
      • 이때 상태 변경에 따른 리렌더링 최적화 필요
    • 저장된 상태를 수정하는 기능
      • 불편성을 유지하면서 상태 업데이트 할 수 있도록
    • 렌더링을 최적화하는 메커니즘을 제공
      • 실제 상태 변경에 따라 리렌더 되어야하는 컴포넌트에서 셀렉터를 구독하도록
      • 사용하지 않는 곳에서는 이 상태를 구독할 필요가 없다 (불필요한 리렌더를 유발할뿐)
    • 메모리 사용을 최적화하는 메커니즘을 제공
  • 이러한 문제를 해결하고자 Redux가 초기 도입되었다
    • 그러나 전역상태 + 로컬 UI 상태 + 원격 API 상태 ....
      •   예를 들어 로컬 UI 상태의 경우 데이터와 해당 데이터를 업데이트하는 메서드 모두 드릴링하는 것은 상황이 커질수록 상대적으로 빠르게 문제가 되는 경우가 많습니다. 이 문제는 상태 끌어 올리기와 함께 컴포넌트 컴포지션 패턴을 사용하면 꽤 깔끔하게 해결할 수 있습니다.
        
      • 현재 마주하고 있는 문제이다
      • 이를 끌어올리거나 컴포지션으로 정리해야하는데...
    • 수 많은 상태들이 분리되기 시작하였다
      • 여기서 또 다른 문제는 모든 상태가 전역에 들어가버릴 수 있다 (정말 불필요했다...)
    •   실제로 많은 웹 애플리케이션은 주로 프런트엔드를 원격 상태 데이터와 동기화해야 하는 CRUD(생성, 읽기, 업데이트 및 삭제) 스타일의 애플리케이션입니다.
      
        즉, 시간을 할애할 가치가 있는 주요 문제는 원격 서버 캐시 문제들입니다. 이러한 문제에는 서버 상태를 가져오고 캐시하고 동기화하는 방법이 포함됩니다.
      
    • 이러한 이유 (=원격 API 상태를 관리하기 위해서)로 리액트 쿼리를 사용하게 되었는데
  • 아직 리덕스, 컨텍스트에서 완전히 빠져나오지 못했으며
  • 잘못된 구독으로 불필요한 리렌더를 유발하는 것을 정리하지 못했다
  • 여기서 다시 보니 반가운 Context는 상태 관리가 아니다

9/1 ~ 9/4

리액트 성능 최적화를 위해

  • (번역) 리액트 성능 최적화, 500ms 에서 1.7ms 까지 : 그 여정과 체크리스트
    • 리액트 메모를 사용해야하는 시점 === 퍼포먼스가 잘 나오지 않다고 느껴지는 경우
    • 습관적으로 메모를 사용하고 있으나 실제로 최적화가 필요한 포인트를 찾아야함
    • 단순히 성능을 개선했다는 것이 아니라 원인이 되는 것을 제거하도록
    • 과도한 메모이제이션🙈
  • 큰 컴포넌트를 잘 정의된 작은 컴포넌트로 분해하고 컴포넌트가 원시 타입의 프로퍼티만을 사용하도록 한다면 리렌더링 최적화를 이끌 수 있다
    • memo로 개선할 수 있지만
    • 원시 타입의 프로퍼티만을 위해서 현재 컴포넌트에 드릴링 되는 무거운 프로퍼티들을 제거하거나
    • diffing 조건을 잘 이렇게 저렇게 하는 작업이...
  • 최근 신경 쓰는 부분: jsx를 const로 변환
    • renderCallback (useCallback<JSX.Element>)이 아닌 RenderComponent (useMemo<JSX.Element>) 또는 RenderComponent (memo)
    • 함수 호출은 항상 발생하고 jsx를 다시 빌드하기 때문에, jsx의 const 변수를 컴포넌트로 변환하는 것이 더 성능이 좋은 것으로 간주할 수 있습니다.
  • 컴포넌트가 리렌더링 되는 이유를 파악하여 그 원인을 해결해야하는데
    • 간단하게 memo가 효과가 있을 수 있으나
    • 결국 원시 타입이 아닌 객체가 재생성되어 리렌더를 유발 시키기 때문에
    • 이런 컴포넌트 트리를 찾아내야한다 🤡

계속 추가되는 비즈니스에 대응하기