ziglog

    Search by

    3월 3주차 기록

    March 17, 2023 • ☕️☕️ 10 min read

    거 너무 더운 거 아니오


    배워가기

    타입스크립트로 1~10만 허용하는 타입 만들기

    enum, union type 등을 사용하지 않고 1 ~ 10만 허용하는 타입 만들기!

    Copy
    type MakeIntLiteral<
      N extends number,
      Acc extends number[] = []
    > = Acc["length"] extends N
      ? Acc[number]
      : MakeIntLiteral<N, [...Acc, Acc["length"]]>;
    
    type T = Exclude<MakeIntLiteral<11>, 0>;

    Ref https://stackoverflow.com/questions/41139763/how-to-declare-a-fixed-length-array-in-typescript

    srOnly

    srOnly는 ‘screen reader only’의 약어로, 화면에서는 안보이지만 screen reader에서는 읽히게 만들 수 있는 부트스트랩의 클래스 중 하나다.

    네이버에서는 blind 라는 className이 같은 역할을 한다.

    Copy
    .sr-only {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0); /* 구형 브라우저를 위해 사용 */
      clip-path: polygon(0 0, 0 0, 0 0); /* inset(50%) 와 동일한 표현 */
      border: 0;
    }

    이벤트스토밍이란?

    Event와 BrainStorming의 합성어로, 도메인 전문가와 개발 전문가가 함께 모여 워크샵 형태로 진행하는 방법론이다.

    시스템에서 발생하는 이벤트를 중심(Event-First)으로 분석하며, 개발까지 필요한 도메인에 대한 빠른 이해를 도모하는데 유리하다.

    input multiple

    <input /> 을 사용할 때 multiple을 이용해서 둘 이상의 요소를 쉼표로 구분하여 받을 수 있다.

    zustand의 persist 미들웨어

    redux-persist와 같은 역할을 해주는 persist 미들웨어가 상태관리 도구 zustand에도 존재한다.

    redux-persist의 역할은, 애플리케이션의 상태를 웹 스토리지(Session Storage, Local Storage 등)에 저장해 앱을 새로고침하거나 나갔다 들어오더라도 해당 상태가 유지되게 해주는 것이다. 이때 persist라는 단어는 atom이나 store처럼 일반적으로 통용되는 식별자로 사용된다. 같은 역할을 해주는 미들웨어나 라이브러리가 zustand, recoil, jotai(jotai의 경우 Persistence) 같은 상태관리 라이브러리들에서 일반적으로 해당 역할을 해주는 기능에 대한 식별자로 쓰이고 있다.

    zustand에서 persist 미들웨어는 다음과 같이 사용한다.

    Copy
    import { create } from "zustand";
    import { persist, createJSONStorage } from "zustand/middleware";
    
    export const useBearStore = create(
      persist(
        (set, get) => ({
          bears: 0,
          addABear: () => set({ bears: get().bears + 1 }),
        }),
        {
          name: "food-storage", // name of the item in the storage (must be unique)
          storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
        }
      )
    );

    Ref https://github.com/pmndrs/zustand#persist-middleware

    <input>의 onChange SyntheticEvent를 직접 디스패치하기 (React 17+)

    • 🙅‍♀️ 틀린 방법

      Copy
      ref.current.value = newValue
      ref.current.dispatchEvent(new InputEvent('input', { ... }))
    • 🙆‍♀️ 맞는 방법

      Copy
      Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(ref.current, newValue);
      ref.current.dispatchEvent(new InputEvent('input', { ... }))

    value에 직접 할당하는 건 왜 안될까? 🤔

    schema.json

    JSON의 스키마를 정의해놓은 파일로, data types, properties 등을 정의할 수 있다. (스키마에 벗어나면 warning도 띄워준다.)

    $schema에 스키마가 포함되어있는 json 파일의 링크를 넣어서 사용할 수 있다.

    Copy
    { "$schema": "https://turbo.build/schema.json" }

    assertion

    • Invariant : 프로그램이 실행 중에 변하지 않아야 하는 조건
    • Assertion : 프로그램에서 참이어야 하는 조건

    💡 Invariant는 안정성을 유지하고 Assertion은 유효성을 검증하는데 사용된다고 한다!

    role=“button” 이모저모

    • (접근성 API에서) role="button" 하위에 있는 시맨틱 요소를 표현할 방법이 없는 대신, 시각적으로라도 표시할 수 있도록 role="presentation"이 자동으로 적용된다.
      • DOM Tree
        • <div role="button"><h3>Title of my button</h3></div>
      • 접근성 Tree
        • <div role="button"><h3 **role="presentation"**>Title of my button</h3></div>
      • 보조기기 사용자 입장
        • <div role="button">Title of my button</div>
    • 단지 **role=“button”**라고 명시하는 것은 버튼 관련 기능을 제공하지 않고, 오직 스크린리더에게 클릭가능한 요소임을 알려주기만 한다.
    • <button> 엘리먼트는 암시적으로 role="button"으로 지정된다.
    • <button> 엘리먼트 role은 다음 중 하나로 변경할 수 있다.
      • checkbox, combobox
      • option, radio, switch
      • link
      • tab
      • menuitem, menuitemcheckbox, menuitemradio

    iOS input color 이슈

    iOS에서 input 텍스트의 색상이 iOS 기본 블루 컬러로 보인다면, appearance: none 이슈일 수 있다.

    appearance 속성은 OS의 테마별 기본 스타일을 설정하는 속성(platform-native styling, based on the operating system’s theme)으로, moz-appearance, -webkit-appearance 속성을 통해 브라우저별 기본 스타일을 설정할 수 있는 기능도 지원한다고 한다.

    Ref https://curryyou.tistory.com/217

    next 명령어

    • next build

      • .next 폴더에 프로덕션 코드를 만들어준다
      • next startnext export 를 실행하기 전에 무조건 실행해줘야 한다.
    • next export

      • pages 하위의 모든 페이지를 서빙 가능한 정적 HTML 파일로 만들어준다
        • out 폴더를 생성하여 그 안에 넣어준다
      • node.js가 아닌 어떤 서버로든 호스팅할 수 있다

    valueof

    valueOf() 메서드는 특정 객체의 원시 값을 반환한다.

    자바스크립트에서 기본적으로 Object의 모든 후손 객체는 valueOf를 상속받는다. 내장된 핵심 객체는 모두 valueOf를 재정의해 적합한 값을 반환한다. 어떤 객체가 원시 값을 가지고 있지 않다면, valueOf는 객체 스스로를 반환한다.

    🧐 뭐하러 필요한 걸까? 🤓 ‘비교’를 위해 사용될 때가 있다. (ex. Date 객체 간 비교)

    식에 연산자가 들어가면, 자바스크립트는 변수의 원시값을 찾아서 연산을 수행한다.

    Ref https://dev.to/composite/valueof-mesodeu-mweohareo-issnya-1n97

    useImperativeHandle

    useImperativeHandle hook은 child component의 상태 변경을 parent component에서 하거나, child component의 핸들러를 parent component에서 호출해야 하는 경우 사용한다. forwardRef와 함께 사용한다.

    Page 컴포넌트에서 자식으로 Search 컴포넌트를 렌더링할 때, 다음과 같이 사용할 수 있다.

    Copy
    // Search.tsx
    export interface SearchRef {
      clear: () => void;
    }
    
    const Search = forwardRef<SearchRef, Props>(props, ref) => {
      const handleClickClearButton = () => {...}
    
      useImperativeHandle(ref, () => ({
       clear: handleClickClearButton,
      }));
    
      return (
        <div>
          <input ... />
          <button onClick={handleClickClearButton}>X</button>
        </div>
      )
    }
    Copy
    // Page.tsx
    const Page = () => {
      const searchRef = useRef<SearchRef>(null);
    
      const someOtherFunction = () => {
        // 🤓 Search 컴포넌트의 useImperativeHandle에서 정의한 메서드를 사용할 수 있다.
        searchRef.current?.clear();
      }
    
      return (
        <div>
          <Search onSearch={(keyword: string) => {...}} ref={searchRef} />
        </div>
      )
    };

    부모는 자식의 DOM에 직접적으로 접근을 하는 것이 아니라 useImperativeHandle로 전달된 메서드에만 접근이 가능해진다. 이로서 더욱 컴포넌트간의 독립성을 보장할 수 있게 된다.

    Ref


    이것저것

    • pnpm publish config - 패키지가 packed되기전에 package.json을 오버라이드할 수 있게 해준다.
    • 다크패턴 - 사람을 속이기 위해 디자인(설계)된 사용자 인터페이스(UI)를 뜻하는 말로, 인터넷 사이트나 애플리케이션에서 사용자들을 은밀히 유도해 물건을 구매하거나 서비스에 가입하게 하는 것이 다크 패턴의 대표적인 사례다.
    • 카카오 픽셀 - 데이터를 수집하여 타겟팅, 카탈로그 소재정보 수집, 전환 보고서, 전환 최적화 등의 다양한 카카오 광고 목적으로 활용할 수 있다. (Ref1, Ref2)
    • margin-top이나 margin-bottom이 auto로 설정되면, 실제로는 0이다. (margin-left, margin-rightauto처럼 동작하지 않는다. - 컨테이너 안에서 요소의 수직 정렬을 맞출 수 없다.)

    기타공유

    개발자 개그를 모아놓은 라이브러리

    devjok라는 라이브러리가 있다.

    세상에… 근데 맘에 든다. 😎

    TypeScript 5.0

    RC를 거쳐 드디어 정식으로 출시되었다! 대표적인 내용은 두 달 전쯤에 올린 포스팅에서 다뤘으니 패쓰.

    Ref

    호주에 있을 때 별건 안하더라도 이거나 틈틈이 봐야겠다 🤓 (과연…)

    Ref https://d2.naver.com/news/7503274

    코드 재사용성의 의미

    코드 재사용성이 과연 경제적으로 가치가 있는 일인지(케이스별로) 고민하게 만드는 글이다.

    • 재사용성을 고려해야 하는 경우
      • 리팩토링: 여러 곳에 중복된 코드가 있고, 중복을 피할 수 있는 추상화를 찾을 수 있다면 재사용 가능한 컴포넌트가 있는 것이다.
      • 재사용할 로직이 매우 복잡하고 전문화되어있는지 확인한다. 예를 들어 암호화 기능을 각각 만드는 것은 좋은 생각이 아니다.
      • 비즈니스 로직이 자주 변경되고 변경될 때마다 여러 시스템을 변경해야 하는 경우
    • 재사용성을 의심해야 하는 경우
      • 재사용 가능한 컴포넌트가 제공하는 기능이 필요하지 않을 경우. “나중에 필요할 것 같다.”라는 막연한 생각은 지양한다.
      • 사용하고자 하는 클라이언트가 거의 없는 경우
      • 새롭게 만드는 것에 대한 공수가 많이 들지 않는 경우
      • 재사용 가능한 기능을 소유한 팀과 많은 커뮤니케이션을 해야 하는 경우
      • 해당 기능이 재사용 가능한지 알 수 없는 경우

    Ref https://yozm.wishket.com/magazine/detail/1930/

    리액트 개발 문서

    가 공개되었다. ‘공식 문서’가 아니고 ‘개발 문서’라니! 나름 이쁘고 리액트를 실작하는 사람들에게 실용적인 것 같다.

    Ref https://react.dev/


    마무리

    호주 3-4월은 한여름 아니고 초가을이라며… 시드니보다 약간 위쪽인 브리즈번은 정말 개덥다. 🥵 34-35도씩 한다. 한여름이잖아! 여름을 정말 싫어하긴 하는데, 땀나서… 근데 의외로 벌레도 별로 없고, 비치도 잘 되어있어서 좋다.

    여기와서 갑자기 외로운 생각도 하고, 업무 시간 외에는 개발이나 공부를 딱히 하진 않으면서 급 고민이 생겼다. 나는 무슨 개발자인지! (아니, 개발자라고 할 수 있는지?🤔) 호주에서 잘 놀고 먹고 쉬고 한국 돌아가면 다시 달려볼 수 있도록 마음가짐의 준비를 좀 해야겠다.

    사진은 금요일 오전에 반차 쓰고 다녀온 스트릿비치🏝️ 도심 한가운데, 숙소에서 도보 15분 거리에 있는데 정말 예쁘다. 여기 와서 한 것 중에 가장 맘에 든다. 수영 잔뜩하고 뱃살 좀 빠졌으려나?

    02

    Relative Posts:

    3월 4주차 기록

    March 24, 2023

    3월 2주차 기록

    March 12, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon