프론트엔드 데브코스 WIL #DAY65~69

에구마·2023년 12월 28일
0

1️⃣4️⃣주차 23.12.18 ~ 23.12.24


✅ 이번주 목표

  • React+TS 과제 개발 기록 ✅
  • 프로젝트 세팅!!!!!!!! ✅

🤨 이번주 배운 것들

  • strapi
  • graphQL

과제를 진행하면서 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 넘기기

forwardRef

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주..? 기획부터 모든 걸 다 프론트끼리 다 해야 하는 거라 굉장히 굉장히 촉박하다 싶으면서도 서비스 운용 목적 아니고 최종 플젝 전 호되게 굴러보기라고 생각하면 그렇게 부담가지지 않아도 될 것 같지만 부담이되고(?)...
공식적으론 금요일부터 프로젝트기간인건데, 마음 급해져서 그전부터 이것저것 알아오면서 팀원들을 독촉했나 싶기도하고 ..^ _ ^


🏃🏻‍♀️ 다음 주

  • 프로젝트 가보자고!!!!!!!

🍰 마무리

다~ 잘될거양..

profile
코딩하는 고구마 🍠 Life begins at the end of your comfort zone

0개의 댓글