July 16, 2022 • ☕️☕️ 8 min read
밀린 일이 많아
storybook에서 preview 에 그려지는 태그들 스타일을 global css파일로 초기화 할 수 있다. 그렇기 때문에 storybook에서 보여지는 컴포넌트들과 실제로 라이브러리에서 배포되어 보여지는 컴포넌트에서 차이가 발생할 수 있다.
별 다른 요구가 없다면 이러한 결과를 방지하기 위해서 storybook에 global css를 배제하여 환경별로 다르게 보이는 경우가 없게 주의하자.
호출 시그니처 (call signatures)는 함수를 어떻게 호출해야 하는지와, 반환이 어떻게 되는지 알려주는 정보이다.
type Add = (a: number, b: number) => number;
const add: Add = (a, b) => a + b;
타입 지정과 함수 구현을 분리해서 작성할 수 있다.
query
next/router 의 useRouter
훅을 통해 router.query
를 불러오려고 했지만 계속 빈 오브젝트 {}
가 나오는 겨웅가 있다.
문서에 따르면 next 에서는 페이지에 getServerSideProps
또는 getInitialProps
가 없을경우 자동으로 정적 최적화(automatic-static-optimization) 을 시전하는데, 이 때 사전 렌더링될 동안 라우터의 query
가 없기 때문에 빈 오프젝트로 나온다고 한다.
그러나 getServerSideProps
를 사용하고 있을 경우, 다른 문제일 수 있다. 관련하여 next.js 깃헙 이슈가 오픈된적이 있다.
해결 방법 중 하나는 클라이언트에서 useRouter
인스턴스 존재를 보장하는 isReady
을 이용하여 query
를 안전하게 부를 수 있다고 한다.
const { query, isReady } = useRouter();
useEffect(() => {
if (!isReady) return;
console.log(query, ": query");
}, [isReady]);
author
의 우선순위가 contents
보다 높다.<a>
는 role=“link”
를 암시적으로 가지고 있다.<img>
태그에 alt=“”
처럼 빈값으로라도 주는 이유는 안주면 src
를 읽어버리기 때문이다.Ref https://www.youtube.com/watch?v=tKj3xsXy9KM
Webpack 4에선 브라우저에서 Node.js API를 사용하기 위한 Polyfill이 자동 적용되었지만, 5에선 이런 Polyfill들이 없기 때문에 별도로 polyfill을 설치해서 지원하는 작업이 필요하다.
Ref https://viglucci.io/how-to-polyfill-buffer-with-webpack-5
relatedTarget
FocusEvent 에는 relatedTarget
이라는 필드가 있어, FocusEvent와 관련된 요소를 알 수 있다.
예를 들어, input
에 onBlur
가 부착되어 있고, input
에 포커스가 있다가 button
으로 포커스를 옮겨서 onBlur
가 호출된다면, onBlur
의 인자로 할당되는 FocusEvent 의 relatedTarget
은 버튼이 된다.
<form>
<input type="text" />
<button type="submit" />
</form>;
document.querySelector("input").onblur = (event) => {
console.log(event.relatedTarget);
};
// input에 타이핑 후 tab 키를 눌러서 button에 포커스가 닿았다면
// button[type=submit] 이 콘솔에 찍힌다
Ref https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget
싱글톤 패턴은 instance 객체를 담을 변수와, 생성자를 private하게 만들어주고 인스턴스를 가져오는 getInstance
메서드를 public으로 사용하여 구현한다.
class Singleton {
private static instance: Singleton;
private constructor() { ... }
public static getInstance(): Singleton {
...
싱글톤은 유닛테스트하기가 어렵다. 모킹을 위한 인터페이스가 드러나지 않고, 각 TC에서도 싱글톤 인스턴스는 유일하기 때문이다.
Ref https://refactoring.guru/design-patterns/singleton#:~:text=It%20may%20be,the%20Singleton%20pattern
보통 key는 map으로 JSX를 생성할 때 유니크한 값을 넣지만 map을 사용하지 않는 경우에도 필요하다는 것에 유의하자.
index로 key를 사용하기도 하지만, 컴포넌트가 추가/삭제/수정되는 컴포넌트의 경우 예상치 못한 결과가 발생할 수 있기 때문에 권장되지 않는다. 다만, 형제요소일지라도 props의 종류가 다르면 key를 고려할 대상이 아니다.
보통 key에 데이터의 id값을 넣지만, id가 없을 때 두 가지 이상의 값을 조합해서 key에 넣을 유니크 키를 만들곤 한다.
여기서 조합한 key가 유니크한지 판단하기 위해 고려해야할 사항은 다음과 같다.
key={'${a}-${b}'}
의 구조는 단순히 보면 a*b
의 경우의 수 이지만 꼭 그런 것은 아니다. a와 b의 조합 경우의 수가 최대 렌더 개수 이하라면, 키 조합이 유니크할지라도 key로서 유효하지 않을 수 있다.jest로 테스트를 돌릴 때, 다음과 같은 에러가 나는 경우가 있다.
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
build/
디렉토리의 파일들이 테스트에 포함되어서 발생하는 문제일 수 있다.
해결책은, jest config에 modulePathIgnorePattterns
를 넣어주면 된다.
// jest.config.js
module.exports = {
modulePathIgnorePatterns: ["<rootDir>/build"],
};
package.json 대신 jest config를 수정하는 것이다.
// package.json
"transform": {
"\\.js$": "<rootDir>/node_modules/babel-jest"
},
CONNECTING-OPEN-CLOSING-CLOSED
의 순서로 상태변화를 한다. (Ref)document.referrer
를 사용하여 현재 페이지로 이동시킨, 이전 페이지의 URI 정보를 알아낼 수 있다.vertical-align
은 inline 요소에만 동작한다..offsetWidth
와 offsetHeight
를 사용한다. 또는 getBoundingClientRect()
를 사용하는데, 이는 CSS 변환을 거쳐 floating-point 넘버가 된다.클래스 필드
in
연산자를 활용한 프라이빗 필드 체크
class MyClass {
#field;
static isMyField(myClass) {
return #field in myClass;
}
}
정규표현식 플래그 d
const matchObj = /(a+)(b+)/d.exec("aaaabb");
// ['aaaabb', 'aaa', 'bb', indices: [[0, 6], [0, 4], [4, 6]]]
모듈에서 최상위 레벨의 await
호출 가능
Promise.all()
로 감싸, 모듈의 비동기 작업이 완전히 완료되기 전에 작업 결과에 접근하지 않도록 한다..at()
Object.hasOwn()
Object.hasOwnProperty()
와의 다른 점은, 정적 메서드로 구현되었기 때문에 특정 인스턴스의 프로토타입 상속 관계에 구애받지 않고 사용 가능하다는 것이다.Error.prototype.cause
에러 체이닝을 위해 도입된 속성이다.
발생한 오류를 다시 한번 감싸서, 추가적인 컨텍스트 메시지를 참조하게 만든 새 에러를 throw하는 방식으로 체이닝할 수 있다.
function job1() {
try {
job2();
} catch (e) {
console.log(e)l
// Error: job2 Error
throw new Error('job1 Error', { cause: e });
}
}
function job2() {
throw new Error('job2 Error');
}
try {
job1();
} catch (e) {
console.log(e);
// Error: job1 Error
console.log(e.cause);
// Error: job2 Error
}
Ref https://yozm.wishket.com/magazine/detail/1570/
일요일에 흠뻑쇼 간다… 갔다와서 써야지 🤩