10일차

osdsoonhyun·2023년 2월 19일
0

코드캠프

목록 보기
7/22

다음주
1. 클릭이 이상해? -> Event-Bubbling / Event-Delegation
2. 바퀴를 재발명 하지마라 -> Library
3. UI의 전체적인 구조를 잡아놓자! -> Layout
4. 다른 페이지도 보여줘! -> Pagination / Infinite-Scroll
5. State 좀 나눠줘 -> Lifting-State-Up

오늘
1. API로 받는 데이터 타입은? -> graphql-codegen
2. 유틸리티 타입도 배워보자 -> Utitility-Type
3. 협업하는데 규칙이 있어야지 -> Eslint / Prettier

포트폴리오 리뷰(댓글)

  1. 댓글 작성하고 등록하는 과정

  2. 등록한 댓글 목록 보여주는 과정

  3. 삭제버튼 눌렀을 때 삭제되는 과정

게시글 상세페이지에서 조립하는법

게시글 상세컴포넌트에 댓글 내장하는법

두 방법 모두 맞고 어느게 낫다하는 것은 상황에 따라 다르다. 서비스 전체에서 게시글이 있고 그 밑에 항상 댓글과 댓글 목록이 있어서 게시글 뿐만 아니라 상품 등록 등에서도 사용된다면 하나로 묶어서 사용하는 것이 좋다
그러나 게시글 등록 따로 댓글이 따로 쓰이거나 UI가 바뀌는 경우는 분리해서 조립하는 방식으로 사용하는 것이 좋다. 이러한 것을 고민하는 것이 프론트개발자의 몫이다.


게시글 목록을 등록했다면 refetch 해줘야 한다. 목록이 7개 있다가 등록하기를 통해 게시글을 추가한다면 백엔드로 Mutation이 날라가고 백엔드는 DB에 저장해준다. DB에는 8개의 목록 데이터가 있으나 화면은 그대로 목록 7개 밖에 보이지 않는데 이때 refetch를 통해 처음에 fetch 한 것을 refetch 하여 다시 가져와 화면에 뿌려준다.

댓글 목록 보기


보통 게시물은 10개씩 보여주고 이것은 기획단계에서 설계를 한 것이다.

emotion을 사용했기에 유지보수가 편해져서 presenter만 보고 무슨 코드인지 알 수 있다.

댓글 삭제

어떤 댓글을 삭제할지 boardCommentId를 찾아 mutation을 날리면 백엔드에서 삭제하고 DB에는 삭제가 되지만 화면엔 변화가 없으므로 refetch를 통해 업데이트(삭제) 된 목록을 보여준다.
삭제할 때에는 어떤 댓글을 삭제할지 댓글 Id를 보내고 refetch할 때에는 게시글과 같이 어떤 게시글에 달린 목록을 불러올지 댓글 전체를 불러오기 때문에 게시글의 Id를 보내야 한다.

비밀번호 입력시 나만의 알림창, 모달창을 구현하지만 지금은 프롬프트로 대체한다.

typescript

타입추론, 타입명시, 불리언타입, 문자열타입, 숫자타입, 배열타입, 객체타입, 함수타입

객체타입의 경우 타입이 없다. 따라서 우리가 명시해주어야 한다.
함수타입 또한 어디서 어떻게 몇 번이든 호출 가능하므로, 타입추론을 할 수 없다 => 반드시 타입명시가 필요하다
따라서 함수타입은 매개변수에서 타입명시를 해놓는다. 그리고 리턴에 대한 타입도 명시해 놓는다

또한 객체에 타입을 명시해놓으면 명시해놓은 타입의 데이터 밖에 못들어오는데 이때 ?를 이용해서 들어올 수도 있고 아닐수도 있다고 해놓으면 에러가 안뜬다.

interface IProfile {
 name: string 
 age: number
 school: string
 hobby?: string
}
 
const profile: IProfile = {
  name:'철수'
  age: 12
  school: "다람쥐초"
}
  
profile.hobby = '테니스'

타입스크립트 실습을 위한 board, codegen 폴더 미리 만들기

BoardWrite 컴포넌트 타입스크립트 전환

BoardWrite 컴포넌트 props 타입 적용

  • 등록페이지에서는 BoardWrite 또한 함수이기 때문에 BoardWrite에 인자로 isEdit이 들어온다고생각해도 된다. isEdit이 객체이므로 객체타입을 받아줘야한다.

  • 수정페이지에서는 isEdit과 data를 보내기 때문에 data 또한 타입명시를 해줘야하는데 fetchBoard가 너무 많으므로 codegen을 사용한다. 지금은 일단 any로 둔다.

  • BoardWrite 함수가 등록페이지, 수정페이지 두 군데에서 실행되고 있다. 함수의 실행이 어디서 어떻게 하는지 다르기 때문에 함수의 인자로 받을 데이터의 타입을 미리 명시해 두어야 한다.

  • 그러고 함수를 실행하는 쪽에서는 타입에 맞게 데이터를 넣어줘야 한다.

  • props에서 data는 있을 수도 있고 없을 수도 있는 존재이므로 ?로 처리해준다.

onChange 함수가 들어오는데 이것은 함수인데 리턴은 없어서 void라 하고 event가 매개변수로 들어오는 함수인데 event는 onChangeEvent가 일어났을때 들어오는 이벤트이다

  • change할때 발생하는 이벤트에 대한 typescript를 ChangeEvent로 만들어주었다.

  • HTML의 어떤 태그를 onChange 했느냐에 따라서 달라지므로 <...>를 통해 어떤 태그인지 명시해준다.

  • 주석 처리한 것처럼 해줘야 하나 React에서 제공해준다.

  • presenter에서 onChange~~ 라는 함수들이 들어오는데 리턴은 없어서 void를 하고 매개변수로 event가 들어오기 때문에 event의 타입도 명시해준다. HTML Input의 onChange가 일어났을 때 들어오는 이벤트이다.

타입스크립트를 위한 graphql-codegen 이해

tab이 아닌 스페이스로 할 것

  • config: typesPrefix: I 하게 되면 IProps 처럼 앞에 I가 붙게 된다.

추가적인 유틸리티 타입 Pick, Omit, Partial, Record 실습

기존의 있는 타입에서 변형해서 나만의 새로운 타입을 만드는 것이 유틸리티 타입이다.

  • Pick
  • Omit
  • Partial
  • Union
  • Record
export default function TypescriptUtilityPage() {
  interface IProfile{
    name: string
    age: number
    school: string
    hobby? : string
  }

  // 1. Pick 타입 -> name, age만
  type aaa = Pick<IProfile, "name" | "age">

  // 2. Omit 타입 -> school만 빼고 
  type bbb = Omit<IProfile, "school">

  // 3. Partial 타입 -> 모두 ?
  type ccc = Partial<IProfile>

  // 4. Required 타입 -> ? 사라짐
  type ddd = Required<IProfile>
  
  // 5. Union 타입
  type eee = "철수" | "영희" | "훈이" // union 타입
  let child: eee
  child = "철수"

  // 6. Record -> Union을 하나하나 분리시켜 적용
  // eee인 "철수", "영희", "훈이" 각각 모두 IProfile이 적용된다.
  type fff = Record<eee,IProfile>

  // ===== (type vs interface) 차이 : 선언병합 ====
  interface IProfile {
    candy: number
  }

  //let profile: IProfile = {} // -> hobby를 제외한 나머지 모두 초기값이 있어야함
  let profile: Partial<IProfile> = {} // -> 상관없다.
  profile.candy = 10
}

type vs interface 차이 : 선언병합

  • 빈 객체를 만들었는데, IProfile은 필수적으로 hobby를 제외하고 나머지 값이 들어가야 한다.
  • 초기값이 없도록하려면 IProfile을 모두 ?로 만들어주면 된다. -> Partial<IProfile>

graphql 기타 타입

useState의 경우 초기값으로 타입추론이 가능하지만, useMutation의 경우는 api 요청해서 받아온 결과 객체는 알 수 없으므로 반드시 타입명시를 해주어야 한다.

const [createBoard] = useMutation(CREATE_BOARD);

const [createBoard] = useMutation<RESULT타입, VARIABLES(인자)타입>(CREATE_BOARD);
const [createBoard] = useMutation<Pick<IMutation,'createBoard'>,IMutationCreateArgs>(CREATE_BOARD);

  • result.data?.createBoard?.meesage에도 안들어올 수 있으므로 ?를 붙여준다.

  • fetchBoard가 없을 수도 있다. -> 언제? fetchBoard가 삭제되었을 때

소소한 꿀팁

함수의 리턴이 없는 것을 void 라고한다.

yarn add typescript --dev
yarn -D add typescript 

-D--dev는 같은 의미, 위치는 상관없다.

0개의 댓글