1️⃣4️⃣주차 23.12.18 ~ 23.12.24
- React+TS 과제 개발 기록 ✅
- 프로젝트 세팅!!!!!!!! ✅
과제를 진행하면서 React+TS 트러블 슈팅 겸 공부한 것 기록들!
useRef의 타입
useRef를 사용하고 타입을 보니 별별 종류가 많았따. MutableRefObject, RefObject, LegacyRef… 서로에게 할당이 안된다는 이슈도 계속 만났다!!
우선 index.d.ts에서 useRef의 타입을 보면 세가지로 선언되어 있다.
function useRef<T>(initialValue: T): MutableRefObject<T>; function useRef<T>(initialValue: T | null): RefObject<T>; function useRef<T = undefined>(): MutableRefObject<T | undefined>;
interface MutableRefObject<T> { current: T; } interface RefObject<T> { readonly current: T | null; } // Bivariance hack for consistent unsoundness with RefObject type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"]; type Ref<T> = RefCallback<T> | RefObject<T> | null; type LegacyRef<T> = string | Ref<T>;
useRef의 제네릭을 주지않으면(undefined) MutableRefObject타입이다.
// 주의 - 이 형태면 ref 속성에 할당이 되지 않는다..! const ref1 = useRef(); //React.**MutableRefObject**<undefined> const ref2 = useRef(null); // React.**MutableRefObject**<null> const ref3 = useRef<HTMLDivElement>(null); // React.RefObject<HTMLDivElement> **// ref 속성의 값으로 사용할 거면 RefObject가 되도록, 이렇게 제네릭 타입을 주자!!!!** const ref4 = useRef<HTMLDivElement>(); //React.MutableRefObject<HTMLElement | undefined> **ref 속성의 타입은 (property) React.ClassAttributes<HTMLDivElement>.ref?: React.LegacyRef<HTMLDivElement> | undefined** 내가 div태그에 달아서 HTMLDivElement 일테고, 결국 **LegacyRef | undefined** 라는 얘기. 위에 type들을 보고 LegacyRef를 생각하면 string| RefCallback | RefObject | { `~~}[] 이게 되네 (아래 에러상황에 이어서)
(에러상황) const ref4 = useRef<HTMLElement>(); //React.MutableRefObject<HTMLElement | undefined> 이렇게 선언하고 ref의 속성으로 할당(ex. <input ref = {ref4} />) 을 하면 다음과 같이 에러가 난다. Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'LegacyRef<HTMLDivElement> | undefined'. Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'RefObject<HTMLDivElement>'. Types of property 'current' are incompatible. Type 'HTMLDivElement | undefined' is not assignable to type 'HTMLDivElement | null'. Type 'undefined' is not assignable to type 'HTMLDivElement | null'.ts(2322) 위의 useRef 세가지 타입 중 세번쨰( MutableRefObject<T | undefined>;)로 선언된 셈이다. 당연함 인자가 () 니까 undefined이니까 ㅇㅇ 근데? 위에서 말했듯 LegacyRef는 string| RefCallback | RefObject | { `~~}[] 니까 들어올수가 없네 그럼 RefObject로 만들어줘야한다. 어떻게? ref4형태를 ref3으로만 만들어주면 된다. 차이는? initialValue유무 !!! const ref4 = **useRef<HTMLDivElement>(null)** 로 선언하여 할당하면 뚝딱~
- 정리
- RefObject의 .current 는 readonly다… ‘Cannot assign to 'current' because it is a read-only property.ts(2540)’ 단, .current.value 수정은 가능
- ref 프로퍼티는 RefObject 값만 받을 수 있다..
useRef<HTML__Element>(null) 이 형태를 사용하자!
마우스이벤트로 x,y 좌표 얻기
“마우스이벤트”에서 얻는 거다. 이벤트가 일어났을 때의 “마우스”의 위치 값이니까!!
마우스오버를 했을 때 콘솔을 찍어보면 다음과 같다
이들 중 좌표로 보이는 것이 clientXY, layerXY, movementXY, screenXY, offsetXY 등이 있는데 각각 무엇인지, 그 중에 무엇을 써볼지 알아가보자
- ClientX, ClientY
현재 보여지는 브라우저 화면 뷰포트 기준으로 x,y 좌표를 반환- OffsetX, OffsetY
이벤트가 발생한 요소!를 기준으로 x,y 좌표 반환- pageX, pageY
스크롤을 포함해서 문서 전체를 기준으로 x,y 좌표 반환- screenX, screenY
모니터 화면을 기준으로 x,y 좌표를 반환
children의 타입은 ReactNode
Property 'children' does not exist on type
interface DetailPageProps {
onClick: () => void;
**children: React.ReactNode;**
}
export const DetailList = ({ onClick }: DetailPageProps) => {
event target 의 클래스네임을 받기 위한 타입가드!
이렇게
e.target**.className**
바로 접근 안됨!e.target이 어떤 요소인지 타입가드로 설정해주기! 참고
<MainPageContainer onClick={(e) => { const { target } = e; if (target instanceof HTMLElement) { console.log(target.classList); // const classList = target.classList; // DOMTokenList } }}>
forwaredRef로 컴포넌트에 ref 넘기기
export const ClickedTooltip = forwardRef( (props: { arrow: boolean }, **ref: React.ForwardedRef<HTMLDivElement>**) => { const { arrow } = props; return ( <> <StMoreContainer ref={ref}> {arrow && <StArrow />} <StMoreEach className="more-button">수정</StMoreEach> <StMoreEach className="more-button">삭제</StMoreEach> </StMoreContainer> </> ); } );
부모 노드의 ref 값을 하위 컴포넌트 요소에 ref 속성의 값으로 둘 수 있다.
하위 컴포넌트를forwareRef()
로 감싼다.
forwardRef( (props, ref ) => { } )
첫번째 인자인 props는 부모에서 넘어온 나머지 props들이고 두번째 ref가 부모 컴포넌트로부터 받은 ref 속성값이다.(객체 혹은 함수임)
백엔드를 간단하게나마 다뤄보는 강의가 주였고, 찍먹해보고 싶었던 Next는 버전문제에 너무 골치 아파서 완성하진 못했다. strapi, graphQL을 다뤄보는건 흥미로웠다! 파이어베이스처럼 가볍게 만들어둘 수 있을 듯한 간단 백엔드 느낌? 근데 낯선 것들이 많아서 이것저것 찾다보면 크롬탭이 마비가 되요 ..
백엔드를 이래저래 해보다가도 프로젝트 고민때문에 제대로 손에 안잡히는 느낌이라, 그냥 프로젝트 셋업에 집중했다.
프로젝트 따지고 보면 한 3주..? 기획부터 모든 걸 다 프론트끼리 다 해야 하는 거라 굉장히 굉장히 촉박하다 싶으면서도 서비스 운용 목적 아니고 최종 플젝 전 호되게 굴러보기라고 생각하면 그렇게 부담가지지 않아도 될 것 같지만 부담이되고(?)...
공식적으론 금요일부터 프로젝트기간인건데, 마음 급해져서 그전부터 이것저것 알아오면서 팀원들을 독촉했나 싶기도하고 ..^ _ ^
다~ 잘될거양..