전역 상태 사용 - useContext()

프론트 깎는 개발자·2023년 1월 8일
1

react hooks

목록 보기
5/5

본 포스팅은 'React Hook' 에 대한 시리즈 게시글 중 5번째 게시글로, useContext에 대해 중점적으로 다루고 있습니다!

Intro

useState(), useEffect() 를 너머, 이제 공식 문서상 마지막 기본 hook 인 useContext() hook 을 다룰 차례이다.

useContext() 가 우선 어떤 상황에 유용할 수 있는지 아래 예시를 바로 보면서 확인해보자.

(참고) 현재 폴더 구조는 아래와 같다

// src/common/useContext/index.js

import UserContainer from 'common/useContext/UserContainer'
import React, { useState } from 'react'

function UseContextPage() {
  const [user, setUser] = useState({
    name: "홍길동",
    age: 20,
    school: "SKKU",
  })

  return (
    <div>
      <h1>
        UseContextPage
      </h1>
      <button onClick={() => { setUser({ ...user, name: "홍길순" }) }}>
        유저 바꾸기
      </button>
      <UserContainer user={user} />
    </div >
  )
}

export default UseContextPage
// src/common/useContext/UserContainer/index.js

import UserCard from 'common/useContext/UserContainer/UserCard';

function UserContainer(props) {
  return (
    <div>
      <h2>UserContainer</h2>
      <p>UserContainer 컴포넌트에서 {JSON.stringify(props.user)} prop 을 받아왔습니다. </p>
      <UserCard user={props.user} />
    </div>
  )
}

export default UserContainer
// src/common/useContext/UserContainer/UserCard/index.js

import UserName from 'common/useContext/UserContainer/UserCard/UserName'
import React from 'react'

function UserCard(props) {
  return (
    <div>
      <h3>UserCard</h3>
      <p>UserCard 컴포넌트에서 {JSON.stringify(props.user)} prop 을 받아왔습니다. </p>
      <UserName user={props.user} />

    </div>
  )
}

export default UserCard
// src/common/useContext/UserContainer/UserCard/UserName/index.js

import React from 'react'

function UserName(props) {
  return (
    <div>
      <h4>UserName</h4>
      <p>UserCard 컴포넌트에서 {JSON.stringify(props.user)} prop 을 받아왔습니다. </p>
      <p>사용자의 이름은: {props.user.name}</p>
    </div>
  )
}

export default UserName

길고 여러 파일에 나누어 져서 복잡한 코드처럼 보이지만, 실상은 아래의 결과를 내는 아주 단순한 코드이다.

여기서 무엇을 말하고나 하는 것일까?

코드를 잘 보면, UseContextPage 라는 최상단의 페이지 컴포넌트에서 제공되는 user 은 정작 컴포넌트 트리 저~ 아래의 UserName 에서 사용되고 있는데, 중간 컴포넌트들인UserContainerUserCard 에서는 사용되지 않음에도 불고하고, UserName 이 필요하다고 하니까 중간에 단순히 이 데이터를 props 로 전달만 해 줄 수 밖에 없는 상황인 것이다.

즉, 특정 데이터가 필요 없는데 단순히 "전달" 목적으로 props 들이 내려가는 경우가 생긴다. 이를 가리키는 용어가 있는데 바로 prop drilling 이다.

해당 컴포넌트에서 사용하지도 않을 prop 을 단순히 전달 목적으로만 이렇게 내려주게 되면, 코드의 가독성이 떨어지고, 하부 컴포넌트로 갈수록 데이터에 문제가 생겼을 경우, 하나 하나 상위 컴포넌트를 추적해가며 잘못된 지점을 찾는 것이 어려워진다.

따라서 단순히 "전달" 만 하는데도 prop 을 넘겨 주는 경우들을 제거할 때 사용하는 것이 react 에서 기본 제공하는 Context API 이다.

Context API

여기서부터 사용되는 도식 및 그림 설명은 개발자 hoon5083 님의 자료를 참고했습니다 😀

현재의 문제를 나타내자면 아래와 같다.

만들어지고 사용되는 곳은 맨 위와 맨 아래 컴포넌트인데, 둘 사이에 UserContainerUserCard 라는 컴포넌트를 타고 오는 것이다.

그래서 추적이 어려워지고, 코드를 읽기 어렵게 만드는 현상을 해결하고자, 아래와 같은 구조를 생각하게 된 것이다.

이런 식으로 작성을 하면 특정 data 가 필요하지 않은 컴포넌트는 불필요하게 prop 을 받지 않아도 돼서 더 클린한 코드를 유지할 수 있다. 아래와 같이 구현을 하면 된다.

import UserContainer from 'common/useContext/UserContainer'
import React, { createContext, useState } from 'react'

export const MyContext = createContext()

function UseContextPage() {
  const [user, setUser] = useState({
    name: "홍길동",
    age: 20,
    school: "SKKU",
  })


  return (
    <MyContext.Provider value={user}>
      <div>
        <h1>
          UseContextPage
        </h1>
        <button onClick={() => { setUser({ ...user, name: "홍길순" }) }}>유저 바꾸기</button>
        <UserContainer />
      </div >
    </MyContext.Provider>
  )
}

export default UseContextPage
// src/common/useContext/UserContainer/UserCard/UserName/index.js

import { MyContext } from 'common/useContext'
import React, { useContext } from 'react'

function UserName() {
  const user = useContext(MyContext)

  return (
    <div>
      <h4>UserName</h4>
      <p>사용자의 이름은: {user.name}</p>
    </div>
  )
}

export default UserName

이런 식으로 user 데이터에 대한 context 를 생성해서 전역 상태로 넘겨 주면, 필요한 컴포넌트에서 useContext() 를 통해서 받아올 수가 있다!

결론

Context 같은 경우 React 에서 기본적으로 제공하는 전역 상태 (관리) 툴 중 하나이다. 보통은 이보다 더 많은 기능을 제공하는 Redux 나 Zustand 도 많이 사용한다. 그리고 data fetching 과 함께 상태 관리를 하고 싶다면, SWR 도 많이 사용하는 편이다!

전역 상태 관리가 장점만 있는 것은 아니고, 단점도 있다. 우선, 컴포넌트 재사용이 어려워지며, 특정 전역 상태를 사용하는 컴포넌트는 그 상태가 변하면 전부 rerender 돼서 성능 이슈가 있을 수도 있다.

profile
Comfort Zone 에서 벗어나자!

1개의 댓글

comment-user-thumbnail
2023년 1월 15일

이렇게 보니 반가운 ppt 페이지 군요 하하

답글 달기