March 17, 2023 • ☕️☕️ 10 min read
거 너무 더운 거 아니오
enum, union type 등을 사용하지 않고 1 ~ 10만 허용하는 타입 만들기!
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
는 ‘screen reader only’의 약어로, 화면에서는 안보이지만 screen reader에서는 읽히게 만들 수 있는 부트스트랩의 클래스 중 하나다.
네이버에서는 blind
라는 className이 같은 역할을 한다.
.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
을 이용해서 둘 이상의 요소를 쉼표로 구분하여 받을 수 있다.
redux-persist
와 같은 역할을 해주는 persist
미들웨어가 상태관리 도구 zustand
에도 존재한다.
redux-persist의 역할은, 애플리케이션의 상태를 웹 스토리지(Session Storage, Local Storage 등)에 저장해 앱을 새로고침하거나 나갔다 들어오더라도 해당 상태가 유지되게 해주는 것이다. 이때 persist라는 단어는 atom이나 store처럼 일반적으로 통용되는 식별자로 사용된다. 같은 역할을 해주는 미들웨어나 라이브러리가 zustand, recoil, jotai(jotai의 경우 Persistence) 같은 상태관리 라이브러리들에서 일반적으로 해당 역할을 해주는 기능에 대한 식별자로 쓰이고 있다.
zustand에서 persist
미들웨어는 다음과 같이 사용한다.
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+)🙅♀️ 틀린 방법
ref.current.value = newValue
ref.current.dispatchEvent(new InputEvent('input', { ... }))
🙆♀️ 맞는 방법
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(ref.current, newValue);
ref.current.dispatchEvent(new InputEvent('input', { ... }))
value
에 직접 할당하는 건 왜 안될까? 🤔
JSON의 스키마를 정의해놓은 파일로, data types, properties 등을 정의할 수 있다. (스키마에 벗어나면 warning도 띄워준다.)
$schema
에 스키마가 포함되어있는 json 파일의 링크를 넣어서 사용할 수 있다.
{ "$schema": "https://turbo.build/schema.json" }
Invariant
: 프로그램이 실행 중에 변하지 않아야 하는 조건Assertion
: 프로그램에서 참이어야 하는 조건💡 Invariant는 안정성을 유지하고 Assertion은 유효성을 검증하는데 사용된다고 한다!
role="button"
하위에 있는 시맨틱 요소를 표현할 방법이 없는 대신, 시각적으로라도 표시할 수 있도록 role="presentation"
이 자동으로 적용된다.
<div role="button"><h3>Title of my button</h3></div>
<div role="button"><h3 **role="presentation"**>Title of my button</h3></div>
<div role="button">Title of my button</div>
<button>
엘리먼트는 암시적으로 role="button"
으로 지정된다.<button>
엘리먼트 role
은 다음 중 하나로 변경할 수 있다.
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 start
나 next export
를 실행하기 전에 무조건 실행해줘야 한다.next export
out
폴더를 생성하여 그 안에 넣어준다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 컴포넌트를 렌더링할 때, 다음과 같이 사용할 수 있다.
// 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>
)
}
// 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을 오버라이드할 수 있게 해준다.margin-top
이나 margin-bottom
이 auto
로 설정되면, 실제로는 0이다. (margin-left
, margin-right
의 auto
처럼 동작하지 않는다. - 컨테이너 안에서 요소의 수직 정렬을 맞출 수 없다.)devjok라는 라이브러리가 있다.
세상에… 근데 맘에 든다. 😎
RC를 거쳐 드디어 정식으로 출시되었다! 대표적인 내용은 두 달 전쯤에 올린 포스팅에서 다뤘으니 패쓰.
Ref
호주에 있을 때 별건 안하더라도 이거나 틈틈이 봐야겠다 🤓 (과연…)
Ref https://d2.naver.com/news/7503274
코드 재사용성이 과연 경제적으로 가치가 있는 일인지(케이스별로) 고민하게 만드는 글이다.
Ref https://yozm.wishket.com/magazine/detail/1930/
가 공개되었다. ‘공식 문서’가 아니고 ‘개발 문서’라니! 나름 이쁘고 리액트를 실작하는 사람들에게 실용적인 것 같다.
호주 3-4월은 한여름 아니고 초가을이라며… 시드니보다 약간 위쪽인 브리즈번은 정말 개덥다. 🥵 34-35도씩 한다. 한여름이잖아! 여름을 정말 싫어하긴 하는데, 땀나서… 근데 의외로 벌레도 별로 없고, 비치도 잘 되어있어서 좋다.
여기와서 갑자기 외로운 생각도 하고, 업무 시간 외에는 개발이나 공부를 딱히 하진 않으면서 급 고민이 생겼다. 나는 무슨 개발자인지! (아니, 개발자라고 할 수 있는지?🤔) 호주에서 잘 놀고 먹고 쉬고 한국 돌아가면 다시 달려볼 수 있도록 마음가짐의 준비를 좀 해야겠다.
사진은 금요일 오전에 반차 쓰고 다녀온 스트릿비치🏝️ 도심 한가운데, 숙소에서 도보 15분 거리에 있는데 정말 예쁘다. 여기 와서 한 것 중에 가장 맘에 든다. 수영 잔뜩하고 뱃살 좀 빠졌으려나?