Context API

leitmotif·2022년 3월 4일
0

Frontend 개인 공부

목록 보기
22/28

개요

다들 Context...문맥..맥락... 뭐시기... 얘기한다. 그래서 Context API가 뭔데?

문제의 발생

  1. 부모 컴포넌트의 state를 최하위 컴포넌트에게 넘겨야하는 경우.
  2. 많은 하위 컴포넌트같은 props를 전달받아야되는 경우.

두 가지를 코드로 작성해보겠습니다.

const [test,setTest] = useState('')

<Parent>
	<FirstChild test={test}/>
</Parent>
 // Parent.js
 
<FirstChild>
	<SecondChild test={props.test}/>
</FirstChild>
 // FirstChild.js
 
<SecondChild>
	<LastChild test={props.test}/>
</SecondChild>
 // SecondChild.js

사실 이런 방식의 Props drilling은 문제가 되지는 않습니다.

링크 : https://ichi.pro/ko/keomponeonteu-guseong-eul-sayonghayeo-reacteseo-prop-drilling-eul-pihaneun-bangbeob-215688422481435

실제로 위의 링크에서는 2 ~ 3 레벨 정도는 괜찮다고 언급하고 있습니다.

그러나 만약 예시 코드의 LastChild 안에도 깊숙히 파고 들어가는 컴포넌트들이 있다면요..?

const [test,setTest] = useState('')

<Parent>
	<First test={test}/>
    <Second test={test}/>
    <Third test={test}/>
    <Fourth test={test}/>
    <Fifth test={test}/>
</Parent>

두 번째 코드입니다.

첫 번째의 이슈는 없겠지만 보기에 좋아보이지 않습니다. 만약 Parent 컴포넌트 안에 또 다른 컴포넌트들이 줄줄이 추가되어야 하는 상황이고 모두 test state를 전달받아야 한다면요? 이거이거... 가독성도 떨어지고 애꿏은 손가락만 바빠질텐데, 어떻게 해결할 수는 없는 걸까요?

너희를 구원하리라. Context API!

문제를 해결하기 위해 React는 Context API를 제공하고 있습니다.

각 레벨마다 명시적으로 props를 넘겨주기 보다는, 기준점이 되는 컴포넌트Context를 선언하고! 그 곳에 전달하고자 하는 값을 담아주기만 하면 자식 컴포넌트들, 또 그 안에 있는 자식의 자식의 자식의........... 컴포넌트들 모두! 공유할 수 있게 됩니다.

Context로 값을 넘겨보자.

const [test,setTest] = useState('')
export const ParentContext = React.createContext();

<Parent>
	<ParentContext.Provider value={test}>
		<Childs/>
	</ParentContext>
<Parent>

Context 객체는 value={} 에 공유하고자 하는 값을 담는 저장소입니다.

Provider는 하위 컴포넌트들에게 value에 해당하는 값을 전달하며, 그들의 변동 여부를 알립니다.

말이 어렵지만... 사실은 간단합니다.
React는 state가 변경되면 다시 렌더링되잖아요?

Context로 값을 받아보자.

어떻게 넘기는지는 알겠다! 그럼 어떻게 받아오는거야?

2가지 방법이 있습니다. 첫 번째는 useContext 훅을 사용하는 방법입니다.

import {useContext} from 'react'
import ParentContext from '../Parent'

const {test} = useContext(ParentContext);

<Childs>
	{test}
</Childs>

미주알 고주알 떠들 것 없이 매우 간단합니다!

두 번째는 Consumer를 사용하는 방법입니다.

import ParentContext from '../Parent'

<Childs>
	<ParentContext.Consumer>
		{ parentState => (
        		<HOne> {parentState} </Hone>
        	)
        }
	</ParentContext>
</Childs>

Consumer는 Context에 담긴 값을 받아서 사용하는 역할을 수행합니다.

갑자기 인자의 이름으로 parentState 가 나와서 당황하셨을 것 같습니다. 인자로서 Context의 value에 담긴 값들이 넘어올 뿐이고 그것을 지칭하는 것은 개발자가 임의로 설정하면 됩니다.

잠깐만요, useContext와 Consumer에는 중요한 차이점이 있습니다.

만약 Context에 여러 개의 값을 담아 전달해야되는 상황이 있는 경우.

1. useContext는 value={test,test2} 이런식으로 받아도 전혀 문제 없습니다.
2. Consumer
 2-1. 여러개의 Provider를 중첩해서 쌓거나
 2-2. 전달되는 value가 Object 형태로 전달되어야 합니다.

이러한 특성 덕분에 저는 useContext를 더 많이 사용하고 있습니다.

근데 Context, 항상 써도 돼?

export const ParentContext = React.createContext();

<Parent>
	<ParentContext.Provider value={test,test2,test3}>
		<First/>
        <Second/>
        <Third/>
	</ParentContext>
<Parent>

예를 들어서 이런 구조로 되어있다고 칩시다.

First는 test를, Second는 test2를, Third는 test3을 가져온다고 가정합니다.

First 컴포넌트에서 test 값을 갱신하면 Provider는 value가 변동되었다고 하위 컴포넌트에 알리게 되고, 그 말은 즉슨 First 컴포넌트만 재렌더링되면 될 것을 그 외 2개의 컴포넌트도 포함시키게 되어 성능상의 이슈가 발생하게 됩니다.

즉, 위와 같은 경우는 Context를 쓰기에는 부적합하다고 느낍니다. 차라리 각 컴포넌트가 test, test2, test3 state를 가지고 제어하는 것이 맞을 것 같습니다.

또 결국 value에 담겨진 값을 가져온다는 것은 정해진 것을 가져온다는 느낌이 강한데, 어떻게 보면 컴포넌트의 재사용을 힘들게 만드는 주범이 되는 것은 아닐까? 라는 생각을 해보게 됩니다.

다시 언급해봅니다.
Context는 맥락 이라는 사전적인 의미를 가지고 있습니다.

아하! 관심사의 분리에 따라 엄격히 사용해라! 라고 말하는 것 같습니다.

profile
제가 그린 것으로 하여금, 동기를 일으키는 개발자가 되고 싶습니다.

0개의 댓글