[React 기초 다지기] ContextAPI

YUZAMIN
Hello, World! I'm YUZAMIN, a diligently endeavoring frontend developer 🐤💦
[React 기초 다지기] ContextAPI

ContextAPI

action, dispatch, reducer의 관계

action

  • action의 type은 액션의 이름, 나머지는 데이터들
1
2
// number라는 상태를 0으로 변경하는 액션 객체이며 액션의 이름은 'SET_NUMBER'
{type: 'SET_NUMBER', number: 0}

dispatch

  • 액션 객체 발행

    • dispatch를 통해 액션을 실행하는 것
1
2
3
4
5
6
7
8
9
const onClickButton = useCallback(() => {
  dispatch({ type: 'SET_NUMBER', number: 0 })
}, [])

return (
  <>
    <div onClick={onClickButton}></div>
  </>
)

reducer

  • 디스패치한 액션을 해석하여 state를 직접 변경해주는 함수
    • 디스패치 할 때마다 reducer 실행됨
    • state를 수정하기 위해서는 이벤트가 실행될 때 액션을 실행(디스패치)해서 state를 바꿔야 하며, state를 어떻게 바꿀 것인지는 reducer에 기록
  • 불변성 지키기

    • 기존 state를 직접 바꾸면 안되고, 새로운 state를 만들어서 바뀔 부분만 바꿔준 뒤, 그 새로운 state로 기존 state를 대체해야 함
1
2
3
4
5
6
7
8
9
10
const reducer = (state, action) => {
  switch (action.type) {
    case 'SET_NUMBER':
      // state.number = action.number (x)
      return {
        ...state,
        number: action.number,
      }
  }
}

ContextAPI 사용하기

사용법

  • ContextAPI에서 접근 가능한 데이터들에 접근하고자 하는 컴포넌트들을 Provider로 묶어주기
    • Provider의 value로 state와 dispatch 함수를 넣어주면 감싸진 컴포넌트들에서 사용 가능함
  • 성능 최적화

    • 해당 Provider 코드가 있는 컴포넌트가 새로 리랜더링 될 떄마다 value 객체도 새로 생성됨 -> ContextAPI를 사용하는 컴포넌트들도 매번 새로 리랜더링 됨
    • 따라서 useMemo를 사용한 캐싱 필요
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const NumberContext = createContext({
  number: 0,
  dispatch: () => {},
})

const value = useMemo(() => ({ number: state.number, dispatch }), [
  state.number,
])
// dispatch 함수는 절대 바뀌지 않기 때문에 useMemo의 dependency array에 넣지 않음

return (
  <NumberContext.Provider value={value}>
    <Table />
    <Form />
  </NumberContext.Provider>
)
  • dispatch 함수를 하위 컴포넌트에서 사용하기

    • 우선 해당 함수를 초기값으로 갑고 있는 context를 export
    • 사용하고 싶은 하위 컴포넌트 파일 내에서 import -> useContext를 사용하여 변수에 할당하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// app.js
export const NumberContext = createContext({
  number: 0,
  dispatch: () => {},
})

// Form.js
import { NumberContext } from './app'

const Form = () => {
  const number = useState(10)
  const value = useContext(NumberContext)

  // ...
  const onClickButton = useCallback(() => {
    dispatch({ type: SET_NUMBER, number })
  }, [number])
}

참고