: 전역에서 사용할 수 있는(여러
컴포넌트에 사용되는) state
하나만 만들어서 모든 컴포넌트에 사용가능!
useQuery에서 받아온 데이터를 props drilling을 하지 않아도 되고 굉장히 편리해진다.전역상태관리(global state) 툴로는 context-Api, Redux, Recoil등이 있다.
✅ fetchPolicy
apollo-client의 고급 기능을 먼저 살펴보자면,
여러 컴포넌트가 있고, 여러 컴포넌트들이 공유할 수 있는 global state가 있다고 할때,
apollo-client로 global state를 만들게되면 Apollo-Cache 라는곳에 저장된다.만일 2번 컴포넌트에서 useQuery를 해오게 되면 useQuery를 해서 받아온 데이터가 Apollo-Cache에 저장된 후 컴포넌트로 들어오게 된다.
이후에 3번 컴포넌트에서 같은 데이터를 요청하게 되면,
Apollo-Cache 에 먼저가서 데이터가 있는지 확인하고
없으면 백엔드에 요청을
있으면 백엔드에 요청을 하지 않고 컴포넌트로 바로 보내주게 된다.이를 Apollo-client의 fetchPolicy(fetch 정책)라고 한다.
- fetchPolicy의 기능
“cache-first” default → 캐시에 있는지 먼저 확인
“network-only” → 캐시에 있든 없든 무조건 백엔드에 요청
(새로고침 전까지 기존거 보게끔 하면 비용절감 - sns서비스 같은데 유용함)
[실습]export default function StaticRoutingPage(): JSX.Element { const { data } = useQuery<Pick<IQuery, "fetchBoards">, IQueryFetchBoardsArgs>( FETCH_BOARDS, { fetchPolicy: "network-only", //이전경험 상관없이 무조건 새거 받아옴, default는 cache-first
- cache-first
글로벌스테이트에 있는 걸 임시저장한다고 본다.
글로벌스테이트에 저장하는 용도는 서버데이터 캐싱을 위한 목적이 대부분!
✅ Recoil
프론트에서 관리하는 데이터라고 해봤자 많은 부분을 차지하지 않을 텐데 Redux를 사용하기에는 너무 헤비하여 어렵고 비효율 적이기 때문에 recoil을 사용한다.
설치명령어:
yarn add recoil
3중에 하나를 선택해서 쓰는게 트렌드!
app.tsx 파일에서 세팅!
import { RecoilRoot } from "recoil"; export default function App({ Component }: AppProps): JSX.Element { return ( <div> <RecoilRoot> <ApolloSetting> <> <Global styles={globalStyles} /> <Layout> <Component /> </Layout> </> </ApolloSetting> </RecoilRoot> </div> ); }
- src -> commons -> stores -> index.ts
// globalstate import { atom } from "recoil"; export const countState = atom({ //고유함. 딱 하나 key: "countState", default: 0, });
Recoil에서는 Atom으로 state의 일부를 보여준다.
그리고 컴포넌트들은 자신이 필요한 Atom을 참조하고 있다.
따라서 자신이 참조하고 있는 Atom에 변화가 있으면,
해당 atom을 참조하는 모든 컴포넌트에서 리렌더링이 일어난다.Recoil은 결국 context-api의 단점을 보완한 상태관리 라이브러리 이기때문에 context-api를 기반으로 하고다!
[실습]
- recoil.tsx
import { useState } from "react"; import { useRecoilState } from "recoil"; import { countState } from "../../../src/commons/stores"; import Child1 from "../../../src/components/units/22-global-state/child1"; import Child2 from "../../../src/components/units/22-global-state/child2"; export default function GlobalStateWithRecoilPage(): JSX.Element { // const [count, setCount] = useState(0); const [count, setCount] = useRecoilState(countState); const onClickCountUp = (): void => { setCount(count + 1); }; return ( <div> <div>페이지의 카운트:{count}</div> <button onClick={onClickCountUp}>카운트 올리기!</button> ===================================================== <Child1 /> ===================================================== <Child2 /> </div> ); }
- child1.tsx
import { useState } from "react"; import { useRecoilState } from "recoil"; import { countState } from "../../../commons/stores"; export default function Child1(): JSX.Element { const [count, setCount] = useRecoilState(countState); const onClickCountUp = (): void => { setCount(count + 1); }; return ( <div> <div>자식1의 카운트:{count}</div> <button onClick={onClickCountUp}>카운트 올리기!</button> </div> ); }
- child2.tsx
import { useState } from "react"; import { useRecoilState } from "recoil"; import { countState } from "../../../commons/stores"; export default function Child2(): JSX.Element { const [count, setCount] = useRecoilState(countState); const onClickCountUp = (): void => { setCount(count + 1); }; return ( <div> <div>자식2의 카운트:{count}</div> <button onClick={onClickCountUp}>카운트 올리기!</button> </div> ); }