[React] Context

Saemi Min·2023년 1월 24일
0

처음 만난 리액트

목록 보기
15/17
post-thumbnail

Context란?

Context

일반적인 리액트에서는 컴포넌트의 props를 통한 데이터 전달
여러 컴포넌트에 걸쳐 자주 사용하는 데이터 ex) 로그인 여부, 프로필 정보
- 기존 방식

- Context 사용

: Context를 사용하면 일일히 props를 통해 전달할 필요 없이 데이터를 필요로 하는 컴포넌트에 곧바로 데이터를 전달할 수 있다!
따라서 코드 깔끔, 데이터 한곳에서 관리 -> 디버깅 하기에 유리

언제 Context를 사용하면 좋을까?
여러 개의 Component들이 접근해야 하는 데이터 : 로그인 여부, 로그인 정보, UI 테마, 현재 언어 등

  • 아래 코드는 현재 선택된 테마를 기존 방식을 사용하여 컴포넌트의 props로 전달하는 예제 코드이다.

  • Context를 사용한 코드

무조건 Context를 사용하는 것이 좋은 건 X
=> Context를 사용하기 전에 고려할 점
Component와 Context가 연동되면 재사용성 떨어짐. 그래서 다른 레벨의 많은 컴포넌트가 데이터를 필요로하는 경우가 아니라면 기존의 사용하던 방식대로 props를 통해 데이터를 전달하는 컴포넌트 컴포지션 방법이 적합!


하위 레벨에 있는 Avatar Component가 user, avatarSize를 필요로 하기 때문에 여러 단계를 거쳐 넘겨줌 -> 불필요한 작업이 수행됨. 그리하여 Avatar Component를 변수에 넣어 직접 넘겨줌.(9강 Element Valiable와 같이) 중간 단계에 있는 Component는 Avatar의 user, avatarSize가 필요 없음

중간 레벨의 컴포넌트를 통해 전달해야하는 props를 없애고 코드를 더욱 간결하게 만들어줌.
-> 최상위의 컴포넌트에게 더 많은 권한을 부여해줌
=> 다만 모든 상황이 이 방식이 좋은게 아님.
데이터가 많아질 수록 상위 컴포넌트에 몰려서 점점 복잡해지고, 하위 컴포넌트는 너무 유연해지기 때문이다.

하위 컴포넌트를 여러 개의 변수로 나눠서 전달하는 방법도 있음.

이 방식은 하위 컴포넌트의 의존성을 상위 컴포넌트와 분리할 필요가 있는 대부분의 경우에 적합한 방법이다.
또한 렌더링 전에 하위 컴포넌트가 상위 컴포넌트와 통신해야하는 경우 렌더 프롭스를 사용하여 처리할 수 있다.
BUT! 어떤 경우에는 하나의 데이터에 다양한 레벨에 있는 중첩된 데이터에 접근할 필요성이 있을 수 있음. 그러한 경우에는 이 방법은 못 사용하고 Context를 사용해야 함.
WHY? 해당 데이터와 데이터의 변경 사항을 모두 하위 컴포넌트들에게 BroadCast 해주기 때문이다. Context가 사용하기에 적합한 데이터의 대표적인 예로 현재 지역 정보, UI 테마, 캐싱된 데이터 등이 있다.

Context API

Context 생성

React.createContext()

const MyContext = React.createContext(기본값)

만약 상위 레벨에 매칭되는 Provider가 없다면 기본값이 사용 됨!
기본값으로 undefined를 넣으면 기본값이 사용되지 않음.

Provider 사용

Context.Provider
: 데이터를 제공해주는 컴포넌트 ( 하위 컴포넌트들을 감싸줌 )

MyContext.Provider value={/* some value */}>

cf. consuming 컴포넌트

Provider value에서 주의해야 할 사항

  • Provider 컴포넌트가 재렌더링될 때마다 모든 하위 consumer 컴포넌트가 재렌더링 됨.
    -> value 포함한 객체가 매번 재생성되기 때문
    이를 방지하기 위해서 value를 직접 넣는 것이 아닌 state를 선언하여 state 값을 provider에 넣어줌.

    => state를 사용하여 불필요한 재렌더링을 막음

Class.contextType


: MyClass라는 클래스 컴포넌트는 MyContext 데이터에 접근할 수 있게 된다.
: 이 속성을 사용하게 되면 this.context를 통해 상위에 있는 provider 중에서 가장 가까운 값을 가져올 수 있다. 모든 생명주기에서 this.context를 가져올 수 있음.
참고로 이 API를 사용하면 단 하나의 Context만을 구독할 수 있음.
(클래스 컴포넌트에서 사용하면 됨)

Context.Consumer

: Consumer 컴포넌트는 Context의 데이터를 구독하는 컴포넌트이다.
(함수 컴포넌트에서 사용하면 됨)

function as a child

컴포넌트의 자식으로 함수를 사용하는 방법

Context.displayName

여러 개의 Context 동시에 사용하기

=> Context.provider를 중첩하여 사용

지금까지 Class 컴포넌트에서 Context를 사용하는 방법과 함수 컴포넌트에서 Provider와 Consumer를 사용하여 Context를 사용하는 방법을 배웠다.
Class 컴포넌트는 이제 거의 사용하지 않기 때문에 함수 컴포넌트에서 Context를 사용하는 방법을 이해하고 있는 것이 더 중요함.

useContext() _ 7강 Hook

useContext() Hook을 사용한 예시
함수 컴포넌트에서 Context를 쉽게 사용할 수 있게 해줌

useContext Hook을 사용하면 Context의 값을 다른 방식과 동일하게 컴포넌트 트리 상에서 가장 가까운 상위 Provider로부터 받아오게 된다. 만약 컨텍스트 값이 변경되면 변경된 값과 함께 useContext Hook을 사용하는 컴포넌트가 재렌더링 된다.
그렇기 때문에 만약 useContext Hook을 사용하는 컴포넌트의 렌더링이 꽤 무거운 작업일 경우에는 별도로 최적화 작업을 해줄 필요가 있다. 또한 useContext 훅을 사용할 경우에는 파라미터로 Context 객체를 넣어줘야하는 것을 꼭 기억해야 함.

(실습) Context를 사용하여 테마 변경 기능 만들기

  • ThemeContext.jsx
  • MainContent.jsx
  • DarkOrLight.jsx
  • 결과

  • (테마 변경 버튼을 누름)

Git - 실습 코드

profile
I believe in myself.

0개의 댓글