21일차 - Global State & Context-API

류연찬·2023년 3월 2일
0

Codecamp FE07

목록 보기
21/39

fetchPolicy

recoilcontext-api 를 보기 전에, apollo-client 의 고급 기능을 먼저 보겠습니다.
여러 컴포넌트가 있고, 여러 컴포넌트들이 공유할 수 있는 global state가 있다고 가정하겠습니다.
apollo-client 로 global state를 만들게되면 Apollo-Cache 라는 곳에 저장되게 됩니다.

만일 2번 컴포넌트에서 useQuery 를 해오게 되면 useQuery 를 해서 받아온 데이터가 Apollo-Cache 에 저장된 후 컴포넌트로 돌아오게 됩니다.

이후에 3번 컴포넌트에서 같은 데이터를 요청하게 되면, Apollo-Client 에 먼저가서 데이터가 있는지 확인하고 없으면 백엔드에 요청을, 있으면 백엔드에 요청을 하지 않고 컴포넌트로 바로 보내주게 됩니다.

이를 Apollo-ClientfetchPolicy 라고 합니다.
fetchPolicy 에는 여러가지 기능들이 있으며 변경이 가능합니다.

  • cache-first ::default:: -> 캐시에 있는지 먼저 확인
  • network-only -> 캐시에 있든 없든 무조건 백엔드에 요청

Global State

보통은 state props를 통해 자식 컴포넌트로 데이터 값을 내려줍니다. 근데 props가 컴포넌트가 여러개를 거쳐서 내려야 한다면 거쳐가는 모든 컴포넌트에 명시해줘야 합니다. 그럼 매번 props로 내려줄까요? 이럴 때 사용하는 것이 글로벌 스테이트입니다.


context-API

context-API 는 여러개를 만들 수 있으며, 모든 컴포넌트의 상태를 관리할 수도 있지만 특정 컴포넌트들만 묶어서 관리할 수도 있습니다.
다만, 여러개를 만들경우엔 네이밍을 달리 해주셔야 합니다.

context-API 사용하기

Context를 사용하기 위해서는 기본적인 설정이 필요합니다.
먼저, 최상위 컴포넌트에서 모든 컴포넌트로 전달해줄 State를 담아주는 Context를 설정해보겠습니다.

ContextReact에서 제공하는 createContext 를 사용해서 생성할 수 있습니다.

import { createContext } from 'react';

export const GlobalContext = createContext({
  name: "",
  setName: (_: any) => {}
})

Context 데이터를 사용할 변수에 createContext 함수의 인자값으로 관리할 State들을 객체 형태로 담아줍니다.

ContextState 값을 설정했으니 이제 값을 변경할 수 있는 set 함수도 설정해보겠습니다.

useState 를 이용해 설정한 State의 값들을 만들어줍니다.

import { useState } from 'react'

const App = () => {
  	const [name, setName] = useState('example')
}

방금 생성한 State 값들이 바로 위에서 설정했던 Context의 State 객체에 담겨져 하위 컴포넌트로 출력되는 State가 됩니다.

❗️ 반드시 Context에 설정된 키 이름State로 생성한 키 이름동일하게 설정해주세요!

이제 생성한 State들을 하위 컴포넌트로 뿌려주기 위한 작업을 추가해 보겠습니다.

app.tsx 가 페이지를 그려내는 부분, 즉 return 하는 부분에서 전체 페이지들을 Context로 감싸줍니다.

import { useState } from 'react'
import { GlobalContext } from './context'

const App = () => {
  	const [name, setName] = useState('example')
    
    return (
      <GlobalContext.Provider value={{name, setName}}>
		// children
      </GlobalContext.Provider>
    )
}

이때, Context의 State 값을 제공한다는 의미로 Provider 기능을 사용할 수 있고, value 값으로 전체 페이지로 전달할 State 값들을 넣어줍니다.

이제부터, value 객체에 들어 있는 모든 State 값들은 모든 컴포넌트에서 가져올 수 있는 전역 State 값을 가지게 됩니다.

한번 컴포넌트에서 Context안에 담겨있는 State 값을 가져오도록 해보겠습니다.

import { useContext } from 'react';
import { GlobalContext } from '../../../context'

const ContextTestPage = () => {
  const { name, setName } = useContext(GlobalContext);
  
  return (
    <div>
      저의 이름은 {name} 입니다. // result: '저의 이름은 example 입니다.'
    </div>
  )
}

export default ContextTestPage

컴포넌트 안에서는 useContext 기능을 이용해서 최상위에 설정된 Context의 State 값을 비구조화 할당으로 가져올 수 있습니다.

Recoil

Context-API에는 단점이 있습니다.
바로 provider로 감싸진 부분의 업데이트가 되지 않은 state에도 리렌더가 일어나게 됩니다.
즉, 불필요한 렌더링이 일어나는 것 입니다. 이를 보완해서 나온 것이 Recoil입니다.
Recoil은 단점을 보완해서 나온만큼 업데이트된 state부분만 리렌더를 해줍니다. 또한 Context-API보다 사용법이 간단합니다.

🔔 Recoil도 결국 context-api의 단점을 보완한 상태관리 라이브러리 이기때문에 context-api를 기반으로 하고 있습니다.
Recoil 공식 페이지 - Getting Started


Recoil 설치

npm install recoil
or
yarn add recoil

Recoil 세팅

세팅은 최상위 부모 컴포넌트에서 진행하시면 됩니다.

import { RecoilRoot } from 'recoil';

const App = () => {
  return (
    <RecoilRoot>
      // children
    </RecoilRoot>
  )
}

export default App

Recoil 사용

Recoil에서는 Atom으로 state의 일부를 보여줍니다.
그리고 컴포넌트들은 자신이 필요한 Atom을 참조하고 있습니다. 따라서 자신이 참조하고 있는 Atom에 변화가 있으면, 해당 atom을 참조하는 모든 컴포넌트에서 리렌더링이 일어납니다.

export const textState = atom({
  key: 'textState',	// state의 이름
  default: ''		// 초기값
})

위의 아톰을 실제로 사용하기 위해선 useRecoilState를 사용해야 하는데, 사용법은 useState와 비슷합니다.

import { useReocilState } from 'recoil'
import { textState } from '../../store/atom'

const TextInput = () => {
  const [text, setText] = useRecoilState(textState);
  
  const onChange = (event) => {
    setText(event.target.value);
  }
  
  return (
    <div>
      <input type='text' value={true} onChange={onChange}/>
      <br />
      Echo: {text}
    </div>
  )
}

export default TextInput

위와 같이 사용하게 되면, textState를 참조하고 있는 모든 컴포넌트에서 재렌더가 일어나게 됩니다.

0개의 댓글