ziglog

    Search by

    8월 4주차 기록

    August 28, 2022 • ☕️☕️☕️ 13 min read

    마지막 여름 휴가


    배워가기

    react 18의 변경사항

    react 18버전부터는 root에서 ReactDOM.render 대신 ReactDOM.createRoot(rootNode).render의 형식으로 DOM을 렌더링한다.

    이때 StrictMode 환경에서 createRoot를 사용하는 경우 react-router-dom v5가 제대로 동작하지 않는다 따라서 StrictMode를 사용하지 않거나, react-router-dom v6를 사용할 것을 권장한다.

    Ref https://github.com/remix-run/react-router/discussions/8768

    react 18에서 useEffect가 2번 실행되는 이유

    react 18의 Strict Mode에서는 useEffect가 2번 실행된다. (development mode에서만) 이는 컴포넌트의 순수성을 보장하기 위해서라고 한다.

    Strict Mode에서 모든 컴포넌트는 다시 mount되기 전에, mount된 후 다시 unmount된다. 즉 각각의 컴포넌트가 mount되고, 그 후 unmount되고, remount된다. 이 과정에서 디펜던시가 없는 useEffect는 2번 호출된다.

    useEffect cleanup 함수를 통해 이 동작을 확인할 수 있다.

    Copy
    useEffect(() => {
      console.log("First call on mount..");
    
      return () => console.log("Cleanup..");
    }, []);

    실행 결과는 다음과 같다.

    Copy
    First call on mount..
    Cleanup..
    First call on mount..

    왜 이렇게 만든 걸까

    컴포넌트를 mount-unmount한 후 두 번째로 mount할 때, react는 첫 번째 mount에서의 state를 원복시킨다. 이는 사용자가

    미래에 react가 state를 보존하면서 UI를 부분적으로 변경/추가/제거할 수 있게 해주기 위한 과도기적 단계의 기능인 것 같다. 예를 들어, 사용자가 화면을 앞 뒤로 전환할 때 react는 이전 화면을 즉시 보여줄 수 있어야 한다. 그래서 컴포넌트가 unmount되기 전에 사용됐던 state를 가지고 remount를 하는 것이다.

    Ref

    에디터 라이브러리

    에디터 라이브러리에서는 사용자가 드래그한 영역을 분간하여 텍스트 스타일을 변경할 수 있게끔 지원해준다.

    또 에디터 라이브러리는 font-size, font-weight 등과 같은 에디터 도구의 기능을 라이브러리 자체의 상태로 가지고 있다. 그렇기 때문에, 사용자 입장에서는 클라이언트의 state를 에디터 라이브러리 state로 변환해주는 맵퍼 함수가 필요하다.

    에디터에서 문단의 형태 (헤딩, paragraph)가 변경될 때는 단순히 폰트 사이즈만 변경되는 것이 아닌, html tag도 적절하게 변경되어야 한다.

    PV vs UV vs Unique Visitors

    • Page View (PV, 페이지뷰)
      • 특정 웹 페이지를 호출 총 횟수 (중복 허용)
    • Unique Page View (UV, 순페이지뷰)
      • 특정 웹 페이지 호출 총 횟수 (중복 제거)
    • Unique Visitors (순방문자,순방문자수, 고유 방문자수)
      • 사이트를 방문한 사용자 수 (중복 제거)
      • GA는 브라우저가 바뀌면 다른 User로 인식한다.
      • 이를 보완하기 위해 Universal Analytics는 User ID를 사용한다

    React에서 children이 없는 컴포넌트 타이핑하기

    VFC를 사용하는 것이 대표적인 방법이다.

    React 18부터는 FC(props: T): ReactElement 수준의 편의제공을 위한 타입으로 바뀌기도 했고, 그 이전부터도 FC/VFC의 부조화가 있었다.

    따라서 (prop: Props): ReactElement 꼴로 타이핑을 하면서, WithChildren 제네릭을 함께 조합할 수 있도록 구성하는 방식을 권장한다.

    next.js의 Switchable Runtime

    next.js의 runtime은 기본적으로 node.js이지만, 상황에 따라서 edge runtime으로 동작한다.

    edge runtime은 미들웨어 및 Edge API 경로에서 사용되는 표준 웹 API를 기반으로 한다. 즉, 이 환경에서 window는 undefined가 아니다!

    react-router-dom의 matchPath

    :id와 같이 url에 들어간 파라미터의 형식에 일치하는지 여부를 확인하는 메서드다. 엄청 유용해보인다!

    Copy
    matchPath("/users/2", {
      path: "/users/:id",
      exact: true,
      strict: true,
    });
    
    //  {
    //    isExact: true
    //    params: {
    //        id: "2"
    //    }
    //    path: "/users/:id"
    //    url: "/users/2"
    //  }

    Ref https://v5.reactrouter.com/web/api/matchPath

    substr vs substring

    사실 substring밖에 써본 적은 없는데, substr도 어디서 들어본 것 같긴 하다. 그런데 deprecated되었다고 한다!

    두 개 메서드 모두 자바스크립트 문자열에서 특정한 구간의 문자열을 추출한다. 파라미터가 조금 다르다.

    substr은 두 번째 인자에 length를 넣는다. 즉 start + length 위치까지를 탐색구간으로 설정한다.

    Copy
    string.substr(start, length);

    substring은 두 번째 인자에 to를 넣는다. to는 탐색 구간이 끝나는 인덱스로, 0부터 시작하는 length라고 볼 수 있다.

    Copy
    string.substring(from, to);
    var str = “coding everybody”; str.substr()  str.substring()
    function(7) everybody  everybody 
    function(0, 7)  coding coding
    function(3, 7) ing eve  ing
    function(7, 2) ev   ding
    function(-7)  erybody   coding everybody
    function(-7, 2) er   co
    function(7, 7) everybo

    Ref https://webclub.tistory.com/20

    regex의 non-capturing group

    reges에서 (?:) 기호의 의미가 궁금해서 알아보니 non-capturing group이라고 한다. 그건 또 뭔지 참~

    출처의 스택오버플로우 글에 설명이 잘 나와있다. 아래 예제를 살펴보자.

    Copy
    http://stackoverflow.com/
    https://stackoverflow.com/questions/tagged/regex

    다음과 같은 regex로 매칭시키면,

    Copy
    (https?|ftp):\/\/([^/\r\n]+)(/[^\r\n]*)?

    다음 결과를 얻을 것이다.

    Copy
    Match "http://stackoverflow.com/"
         Group 1: "http"
         Group 2: "stackoverflow.com"
         Group 3: "/"
    
    Match "https://stackoverflow.com/questions/tagged/regex"
         Group 1: "https"
         Group 2: "stackoverflow.com"
         Group 3: "/questions/tagged/regex"

    하지만 만약 주어진 URL 문자열에서 프로토콜 부분((https?|ftp))을 신경쓰지 않고, host와 path만 얻고 싶다면 non-capturing group을 나타내는 (?:) 기호를 사용할 수 있다.

    Copy
    (?:https?|ftp):\/\/([^/\r\n]+)(/[^\r\n]*)?
    Copy
    Match "http://stackoverflow.com/"
         Group 1: "stackoverflow.com"
         Group 2: "/"
    
    Match "https://stackoverflow.com/questions/tagged/regex"
         Group 1: "stackoverflow.com"
         Group 2: "/questions/tagged/regex"

    즉 주어진 문자열의 앞에서부터 부분적으로 매칭되는 문자열들은 무시, 즉 non-capture하고 오직 전체가 매칭되는 문자열만 반환한다!

    Ref https://stackoverflow.com/questions/3512471/what-is-a-non-capturing-group-in-regular-expressions


    이것저것

    • lexical library에서 registerUpdateListener를 통해 에디터 상태가 업데이트 될 때마다 콜백함수를 호출시킬 수 있다.

    • Gitlab CI/CD의 before-scripts에서 export를 사용해서 선언한 변수는 scripts에서도 사용 가능하다.

    • storybook의 DocsContext 를 사용하면 현재 선택한 스토리를 캔버스에 동적으로 띄워줄 수 있다.

      Copy
      const context = useContext(DocsContext); .... return ( <Canvas> <Story id={context.id} /> </Canvas> )
    • line-height: 0 - 자신의 line-height에 의한 영향을 아예 없앤다. (다른 sibling에 의해 결정되도록 한다.)

    • 도커 빌드를 할 때 docker build --build-arg $ENV=SOME_ENV 명령어를 통해 환경 변수를 넣어줄 수 있다.


    기타

    가면 증후군 (Imposter Syndrome)

    미국 실리콘밸리 재직자 2,965명을 대상으로 진행한 설문 결과, 응답자의 62%가 ‘내가 유능하지 않다는 걸 회사 사람들이 알아채는 것이 두렵다‘고 답했다. https://platum.kr/archives/146093

    아마존의 한 재직자가 ‘나는 경력 19년차인데도 똑같이 느낀다. 아마존으로 옮긴 지 4개월짼데 혹독한 인터뷰를 거쳐 들어온 것임에도 내가 회사 사람들을 속인 것 같이 느껴진다. 당신만 그렇게 느끼는 게 아니다‘고 댓글을 남겼다. 또다른 마이크로소프트의 재직자 역시 ‘나는 마이크로소프트에 10년째 다니는데도 아직도 그렇다’고 공감했다.

    nodejs의 불분명한 builtin과 addons

    node.js에서 “native module”이라는 용어는 node.js 자체의 모듈(ex. fs, http)을 가리킨다. 하지만 동시에 native addons를 가리키기도 해서, 사람들을 혼란스럽게 만든다.

    따라서 새로운 패치 버전을 제안하고 있는데..!

    • node.js 빌트인 자바스크립트 scripts들은 ‘빌트인’이라고 한다. 만약 모듈로 사용이 가능하다면, ‘빌트인 모듈’이라고 칭할 수 있다.
    • node.js에 로드된 동적으로 링크된(Dynamically-linked) 공유 객체들은 ‘addons’라고 한다.

    Ref https://github.com/nodejs/node/pull/44135?fbclid=IwAR20wJ2j_BLa0KBsxrjsNyF3koV_pLNpYd_7DZ9KguaNa-Vx8O34ab8VuwM&mibextid=iloqvq

    Polymorphic한 React 컴포넌트 만들기

    ‘polymorphism’은 한국어로 ‘다형성’이라는 뜻을 가지며, 컴퓨터 과학에서 다형성은 프로그래밍 요소가 여러 형태로 표현될 수 있는 것을 의미한다.

    polymorphic한 UI 컴포넌트는, 코드에 따라 어떠한 요소(element)도 돌 수 있고, 그에 따른 속성(attribute)도 사용할 수 있다. 즉 무엇이든지 될 수 있는 컴포넌트를 가리킨다. 이는 MUI 등의 React와 관련된 UIKit을 살펴보면 많이 사용되고 있는 패턴이다.

    자바스크립트에서 polymorphic 컴포넌트를 구현해보면 다음과 같다. 먼저 가장 추상적인 컴포넌트인 View 컴포넌트를 만든다.

    Copy
    export const View = forwardRef(({ as, ...props }, ref) => {
      const Element = as || "div";
      return <Element ref={ref} {...props} />;
    });

    이 컴포넌트는 다음과 같이 사용한다.

    Copy
    import { View } from "./View";
    
    const App = () => {
      return (
        <div>
          <View as="a" href="https://kciter.so">
            Click Me!
          </View>
        </div>
      );
    };

    View 컴포넌트에 as prop을 넘겨줌으로써 어떤 html tag를 사용할지 유연하게 결정할 수 있다. 같은 코드를 타입스크립트로 작성하면 어떨까?

    Copy
    /**
     * View.tsx
     */
    interface ViewProps<T extends React.ElementType> {
      as?: T;
    }
    
    export const View = <T extends React.ElementType = "div">({
      as,
      ...props
    }: ViewProps<T>) => {
      const Element = as || "div";
      return <Element {...props} />;
    };
    Copy
    /**
     * App.tsx
     */
    import { View } from "./components/View";
    
    const App = () => {
      return (
        // 🚨 컴포넌트 부분에 에러가 발생한다.
        <View as="a" href="https://kciter.so">
          Link
        </View>
      );
    };
    
    export default App;

    React.ElementType은 JSX 내장 컴포넌트 또는 사용자 정의 컴포넌트를 둘 다 받을 수 있는 타입으로 string | React.ComponentType<any>로 정의되어있다. 이 타입과 제네릭을 사용하면 위 자바스크립트 코드에서 했던 것처럼 as를 통해 사용하려는 요소를 바꿀 수 있게 된다.

    하지만 View 컴포넌트를 작성하면, as 를 통해 사용하려고 한 요소가 무엇인지 알 수 없다. 따라서 다음과 같이 View 컴포넌트를 수정해야 한다.

    Copy
    type ViewProps<T extends React.ElementType> = {
      as?: T;
    } & React.ComponentPropsWithoutRef<T>;
    
    export const View = <T extends React.ElementType = "div">({
      as,
      ...props
    }: ViewProps<T>) => {
      const Element = as || "div";
      return <Element {...props} />;
    };

    그런데 이래서는 ref를 받아올 수 없다..! forwardRefref를 받아오는 방법은 출처⬇️에서 마저 확인해보자 😊

    Ref https://kciter.so/posts/polymorphic-react-component

    astro

    아스트로라니… 아이돌 정보왕에게는 그저 차은우가 있는 아스트로가 생각날 뿐이다.

    “MPA + SSR 프레임워크“라고 강조하며, 섬이라는 새로운 구조를 제시한 astro의 1 버전이 릴리즈되었다. Key feature들은 다음과 같다.

    • Component Islands: 더 빠른 웹사이트를 만들기 위한 새로운 웹 아키텍쳐
    • Server-first API design: 사용자 디바이스에서 시간이 오래 걸리는 hydration을 제거
    • Zero JS, by default: 자바스크립트 런타임이 없다(?!)
    • Edge-ready: 어느 곳에나 배포할 수 있다. 심지어 Deno나 Cloudflare같은 글로벌 엣지 런타임도 가능
    • Customizable: Tailwind, MDX, 그리고 수많은 다른 도구들과 통합 가능
    • UI-agnostic: React, Preact, Svelte, Vue, Solid, Lit 등등을 지원한다.

    자바스크립트 코드골프

    최소한의 자바스크립트 코드로 뭔가 멋진 것을 만드는 것을 의미한다. 🙄

    알고리즘 테스트 풀 때 정말정말 코드를 짧게 거의 한 줄로 작성하는 고수들의 코드가 떠오른다…

    Ref https://getbutterfly.com/code-golfing-tips-tricks-how-to-minify-your-javascript-code/

    개발자 가면 증후군

    너무나도 나같아서 와닿는 글이다..! 물론 ‘사회적으로 존경받는 지위나 신분에 이르렀으면서도’라는 전제가 잘못되긴 했지만 🙄

    그냥 미친 경쟁사회에서 아등바등 살아가는 대부분의 사람들이 그렇지 않을까 생각한다.

    아래와 같은 생각을 해본 적 있는지 묻고 있는데,

    1. 나는 개발자가 될 만큼 똑똑하지 못한가 봐
    2. 똑같이 시작했는데 저 개발자가 나보다 훨씬 뛰어난 것 같아
    3. 깊은 컴퓨터공학 지식이 없다는 걸 들키면 어떻게 하지? 나한테 물어보면 어떻게 하지?
    4. 이곳은 나에게 과분한 곳 아닐까?
    5. 내 진짜 실력이 들통나면 어떻게 하지?
    6. 밀려 있는 개발 공부하기에도 바쁘고, 업무하기도 바쁜데.. 이런저런 걱정들로 집중도 안 되고.. 포기할까?
    7. 시간은 지나가는데 무언가 이룬 것은 없는 것 같아서 불안해

    모든 항목이 완전 내 맘을 훑고 있다.

    개발자라는 직업 특성상 어쩔 수 없는 것 같기도 하다. 정말 나같은 별거 아닌 신입 개발자 뿐만 아니라, 세계 굴지의 기업인 MS 개발자도 똑같은 감정을 느끼고 있다니. 그리고 실리콘밸리 재직자의 62%가 비슷한 마음이라니! 그런데도 위안이 되지 않은 건 뭘까. 아무튼 그들은 잘나간다고 생각하는 것 같다.

    이런 현상의 원인으로 엄격한 성장환경과 완벽주의를 들고 있지만, 예상하지 못했던 이유로 ‘코로나19’가 회자된다. 그것도 맞는 것 같다. 동료들과 사적인 대화를 나누며 서로 인간적인 친밀감을 공유할 시간이 거의 없어졌으니… 😂

    가면 증후군을 벗어나는 방법으로는, 미셸 오바마의 태도가 가장 와닿는 것 같다.

    “저에게 자기 의심이 찾아올 때면 저는 그냥 모든 생각을 내려놓고 제 앞에 주어진 걸 했습니다. 그리고 제가 했던 그 일이 저를 대신해서 이야기하게 했습니다.”

    이런저런 생각을 하지 말고, 눈 앞에 주어진 일부터 하자!

    그리고 현실적으로 와닿는 말

    Comfort Zone → Growth Zone에 이르기까지 Comfort Zone에 계속 머물러 있으면, 우물 안 개구리가 되기 십상이죠. 학습은 평생의 여정이고, 새로운 도전에 직면하면 편안함을 확장할 기회로 생각해보는 거예요. 게다가 자신의 결점이나 기술 부족을 인식하는 능력은 실제로 기술을 향상하고 성장하려는 좋은 신호이며, 내가 지금 겪는 고통은 성장통임을 인지해 봅니다.

    Ref https://medium.com/lemonbase/developer-imposter-syndrome-153f4d94c5d8

    타입스크립트 4.8 릴리즈

    언제 4.8까지 나왔다냐… 새로운 기능들은 다음과 같다.

    • Improved Intersection Reduction, Union Compatibility, and Narrowing
    • Improved Inference for infer Types in Template String Types
    • —build, —watch, and —incremental Performance Improvements
    • Errors When Comparing Object and Array Literals
    • Improved Inference from Binding Patterns
    • File-Watching Fixes (Especially Across git checkouts)
    • Find-All-References Performance Improvements
    • Exclude Specific Files from Auto-Imports
    • Correctness Fixes and Breaking Changes

    Ref https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/

    상태 라이브러리

    일본어로 ‘상태’를 의미하는 ‘Jotai’ 상태관리 라이브러리에 이어 한국어 ‘sangte’ 라이브러리가 기어코 나오고 말았다… 리액트의 거장 벨로퍼트님께서 만드셨다.

    Ref https://github.com/velopert/sangte


    마무리

    피트스탑이 어영부영… 끝났다. 2주가 짧은 줄은 알고 있었지만 정말 너무 짧잖아? ㅠ 프론트 테스트 코드는 정말 쉽지 않아.

    주말에는 첫(!) 여름휴가를 우테코 동기들과 함께 다녀왔다. 3년 만에 가보는 가평 빠지! 진짜 사람 너무 많고 차 막히고 죽을 뻔 했지만 모두 신나게 웃고 떠들고 놀고 마시고 배터지게 먹고 숙소를 잘 잡아서 아늑한 곳에서, 쏟아지는 별들을 바라보며 새벽을 보냈다.

    행복했던 시간!


    Relative Posts:

    9월 1주차 기록

    September 2, 2022

    8월 3주차 기록

    August 20, 2022

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon