react + typescript + graphql + apollo

YOUNGJOO-YOON·2021년 9월 5일
0

TS+REACT

목록 보기
8/10
post-custom-banner

중요한 부분만 훑어보자.

import React, { useState, Dispatch,SetStateAction, ChangeEventHandler } from 'react' // 중요 1
import './App.css'
import { gql, useQuery, NetworkStatus } from '@apollo/client'

const GET_DOGS = gql`
{
  dogs{
    id
    breed
  }
}
`

interface GetDogListProps{
  setBreed:Dispatch<SetStateAction<string>> // 중요 2
}

function GetDogList({setBreed}:GetDogListProps){
  const { loading, error, data } = useQuery(GET_DOGS)

  if(loading) return <h1>Loading...</h1>
  if(error) return <h1>{error.message}</h1>

  function onChange(e:React.ChangeEvent<HTMLSelectElement>){ // 중요 3
    console.log('show e: ',e.target.value)
    setBreed(e.target.value)
  }

  return(
  <select onChange={onChange}>
    {
      data.dogs.map((dog:{id:string,breed:string})=>(
      <option key={dog.id}>
        {dog.breed}
      </option>
      ))
}
  </select>
  )
}

const GET_DOG_PHOTO = gql` // 중요 4
query dog($breed:String!){
  dog(breed:$breed){
    id
    displayImage
  }
}
`

interface ShowImageProp{
  breed:string,
}
function ShowImage({breed}:ShowImageProp){
  const {loading, error, data, refetch, networkStatus} = useQuery(GET_DOG_PHOTO,{
    variables:{breed},
    notifyOnNetworkStatusChange:true
  })

  console.log('networkStatus: ',networkStatus)
  if(networkStatus === NetworkStatus.refetch) return <h1>Refetching...</h1>
  if(loading) return <h4>Loading...</h4>
  if(error) return <h4>something wrong...</h4>
  return(
    <>
    <img
    src={data.dog.displayImage} 
    style={{width:100,height:80}} />
    <button onClick={()=>refetch({
      breed:'dalmatian'
    })}>Refetch! dalmatian</button>
    </>
  )
}




function App(){
  const [breed, setBreed] = useState<string>('')


  return(
   <div className='App-header'>
     <h1>{breed}</h1>

    <ShowImage breed={breed} />
    <GetDogList setBreed={setBreed}/>
  </div>
  )
}

export default App

중요 1 & 2

import React, { useState, Dispatch,SetStateAction, ChangeEventHandler } from 'react' // 중요 1

Dispatch Dispatch는 useState의 setter 부분에서 사용되는 타입 선언이다. (아래와 같음)

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

SetStateAction과 Dispatch는 다시 아래와 같다.
type SetStateAction<S> = S | ((prevState: S) => S);

type Dispatch<A> = (value: A) => void;

위 타입을 나열한 목적은 다음과 같다.

자식 component에 useState의 setter를 넘겨주고 싶기 때문이다.


function App(){
  const [breed, setBreed] = useState<string>('')


  return(
   <div className='App-header'>
     <h1>{breed}</h1>

    <ShowImage breed={breed} />
    <GetDogList setBreed={setBreed}/>
  </div>
  )
}

GetDogList는 setBreed라는 setter를 전달 받았다.
App component 자체에서는 에러가 발생하지 않는다.

interface GetDogListProps{
  setBreed:Dispatch<SetStateAction<string>> // 중요 2
}

function GetDogList({setBreed}:GetDogListProps){
  const { loading, error, data } = useQuery(GET_DOGS)

  if(loading) return <h1>Loading...</h1>
  if(error) return <h1>{error.message}</h1>

  function onChange(e:React.ChangeEvent<HTMLSelectElement>){ // 중요 3
    console.log('show e: ',e.target.value)
    setBreed(e.target.value)
  }

자식 component인 GetDogList는 전달 받은 props인 setter를 어떻게 타입 정의해야 할까?

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
위 타입 정의에 따르면 setter는 Dispatch<SetStateAction<S>> 타입을 가진다.

따라서 props는 파일의 최상단에서 선언한 Dispatch,SetStateAction, 타입을 Dispatch<SetStateAction<S>>형식에 맞게 넣어주면 된다.

내가 받아온 breed라는 type은 string이므로 string을 넣어주었다.


중요 3 React.ChangeEvent<HTMLSelectElement>

해당 타입은 vscode에서 자동적으로 추천해주기는 할 것이다.

하지만 select>option의 onChange의 argument 타입은 이 것이다.


중요 4



const GET_DOG_PHOTO = gql` // 중요 4
query dog($breed:String!){ // #1
  dog(breed:$breed){ // #2
    id // #3
    displayImage
  }
}
`

graphql은 사용하기 복잡하기 때문에 문법을 잘 이해해야 한다.

#1

query dog($breed:String!) 은 query를 고른다

#2 query dog의 변수 이름은 breed이고 $breed는 넣어서 보내줄게

#3 원하는 data(key)는 아래와 같다

profile
이 블로그의 글은 제 생각을 정리한 글과 인터넷 어딘가에서 배운 것을 정리한 글입니다. 출처는 되도록 남기도록 하겠습니다. 수정 및 건의 오류 등이 있으면 언제든지 댓글 부탁드립니다.
post-custom-banner

0개의 댓글