grphql variables의 실체
export const CREATE_BOARD = gql`
mutation createBoard($writer:String){--> 이부분에 타입을 적어줌.
createBoard(writer:$writer){
_id
}
}
}`
createBoard({
variables:{
writer: myWriter --> 여기 이부분이 위의 쿼리문의 $writer(얘는 변수) 에 들어감 변수기에 임의로 아무 이름으로 사용이 가능하디/
}
})
쿼리문에 타입을 적어주는 이유: 여러 API를 보낼 수 있다.
restAPI: 요청을 하면 전부다 불러온다.(오버페칭문제)
필요한것을 하나하나 따로따로 요청해야한다(언더페칭문제)
graphqlAPI: 요청시 필요한것만 받아옴.(오버페칭하지않음)
한번에 가져오기 가능.(묶음요청가능)
export const CREATE_BOARD= gql`
mutation 그룹이름 ($asd:String){ ==> 하나의 변수를 여러군데에서 사용할 수 있기에 그것의 타입을 적어준것.
createBoard(writer:$asd){ ==>API 1
_id
}
createProduct(writer:$asd){ ==>API 2
_id
}
}`;
API둘을 그룹핑해서 1번만요청한다.
graphqlAPI는 restAPI이다.
무슨말이냐고?
원래는 restAPI만 존재했다.
등록 POST /boards
조회 GET /boards
상세조회 POST /boards/:id
==> 너무많은 엔드포인트가 생성된다. 따라서 POST방식의 엔드포인트에 graphql을 붙여 사용하여 엔드포인트 문제를 해결했다.
목록으로 뭘 받아올지 적어주고,
하나의 엔드포인트에 함수를 여러개 만들어준다.
적어준 목록에서 보내주는 방식이다.
==> 결국 graphql은 restAPI의 엔드포인트가 하나인 POST 방식에 불과하다.(반드시 POST여야한다)
그래서 이거 실행시켜줘 라는 개념으로 바뀐것이다.
createBoard(writer:"홍",title:"아침")
=> 이런식으로 소괄호 안에 넣어 보내준다.
키와 value의 형식으로 보내주는데 작성법은
{
"query":"createBoard(){
}
uploadBoard(){
}"
}
이런식으로 적어주면 된다.
이렇게 묶어서 보내주게되면 껍데기 API 즉 , 겉의 API는 하나라도 잘 요청된다면 무조건 상태코드 200이 뜬다.
타입에러일 경우에는 상태코드가 400 이지만 그 외에는 200이뜨게된다.
에러가 있을 수도 있으니 네트워크탭 response부분에서 확인이 가능하다.
graphql은 엔드포인트가 하나인 POST방식의 rest API이다. 따라서 postman으로 요청이 가능하다.
글로벌 스테이트.
공통적으로 사용하는 state는 어떻게 해줘야하나?
페이지 컴포넌트가 자식의 자식의 자식.. 에게도 쓰인데 props로 뚫고 들어가는 props drilling방식을 기존에는 사용했다.
==> 모든 컴포넌트가 공유하는 Grobal state가 있다하면 뽑아서 사용하는 식으로 만들어 사용하면 편할것이다.
그런데 직접만들려면 번거롭다. 다행이 잘 만들어놓은 라이브러리가 등장했다.
초창기의 라이브러리는 redux다. 그러나 세팅할것이 많았다. 따라서 다른 여러가지들이 이후에 나왔는데 react-query와 ,apollo/client 를 현재 사용한다.
그런데 글로벌 스테이트에는 크게 두가지로 나뉘어진다.
바로 벡엔드에서 받아오는 데이터를 저장하는 부분과, 프론트 엔드의 데이터를 저장하는 부분이다.
다행이 벡엔드의 데이터는 apollo/client 에서 해주니 이것에 관해 어떻게 저장이되는지만 보면된다.
다만 프론트엔드의 적은 데이터들은 어디에 저장할지가 의문이 들었다.
redux를 사용하자니 너무 복잡해지고 따라서 그것의 미니 버전인 recoil을 사용하도록했다.
일단 벡엔드데이터를 저장하는 fetchPolicy정책을 알아보도록했다.
데이터를 받아오면 글로벌스테이트에 저장되고ㅡ useQuery등이 실행될때 글로벌 스테이트를 확인한 뒤 없으면 요청해 받아오는 방식으로 이루어지는데, 이 방식을 fetchPolicy정책이라고 한다.
default로는 chache-first이다.
일단 글로벌스테이트(글로벌캐시=아폴로캐시)에 일단 캐시가 있는지 확인한다음 있으면 다시 요청하지 않고 있는것을 가져와 사용하는 것이다.
network-only: 그냥 무조건 새것으로 받아오는것이다.
많은 속성들이 있지만 일반적으로 저 두가지를 많이 사용한다.
const {data} = useQuery(FETCH_BOARDS,{fetchPolicy:"network-only"}) ==> 이런식으로 사용한다. 현재 network-only 라고 적었으니 무조건 새로 받아오게된다.
예외사항.
chache-first라도 만약 처음요청해 받아와 저장한것에 그다음 요청한부분의 일부가없다면 즉, 처음에는 contents를 불러오지 않았는데 다음에 같은것을 요청하면서 contents을 추가했을 시 이경우에는 chache-first임에도 불구하고 다시 요청이 들어가 받아온다.
주의: 페이지 전환을 할경우 use로 시작하는 애들을 제외하고 function부분은 다시 리랜더된다.
따라서 저장되었던 캐시는 지워지고 다시요청이 들어가게된다.
new InMemorychache()부분을 funtion밖으로뺀다.
변수에 담아 원래있던 chache: 이부분에 변수를 넣어준다.
const GLOBAL_STATE = new InMemoryCache();
cache: GLOBAL_STATE,
(캐싱 즉 받아온 데이터 저장시에는 반드시 _id나 id가 있어야 제대로된다. 안에서 받는것도 id해주기)
프론트엔드에서 자체적으로 생성되는 데이터 관리위해 미니 redux인 recoil을 설치한다.
yarn add recoil
설치 후 _app.tsx에
<RecoilRoot>원래 내용물</RecoilRoot>
이렇게 적어 이 내부 전체에 Recoilstate를 사용하겠다고 만들어준다.
recoil에 저장해 recoil에서꺼내오는 방법
state를 만든다. 단, useState()대신에 useRecoilState()를 사용한다
소괄호 안에 들어갈 것은 src폴더의 commons의 라이브러리의 store폴더 안에 만들어 놓았다,
export const isEditState = atom({
key: "isEdit" ==> 헷갈리지 않게 변수명과 동일하게 설정
default:flase==>초기값 지정
해당 컴포넌트를 임폴트하여
const [isEdit,setIsEdit] = useRecoilState(isEditState)
useEffect(() => {
setIsEdit(true);
}, []);
// 참고로 useEffect없이 setIsEdit만을 사용할수는 없다. 어디 안에서 선언되어야한다고 떴던거같다.
그리고, true라고 명확하게 적어줘야한다. 페이지가 리페치될때마다 useEffect가 실행되는데, prev로 적으면 그때그때 값이 다르게 나오게된다.
소괄호 안에 이렇게 적어준다.
==>이렇게 넘겨줄 부분과 받을 부분에만
const [isEdit,setIsEdit] = useRecoilState(isEdit)
이렇게 써주고 임폴트를 해주면 props드릴링없이 사용가능하다.