의미는 알고 있었으나 사용해볼 일이 없었던 context api. 이 글은 회사 소스 코드를 보다 자유자재로 context api가 사용되는 것을 보고 정리를 해야할 필요성을 느껴서 작성하는 글이다.
기본적으로 react에서는 컴포넌트끼리 데이터를 주고받을때 props
로 데이터를 전달한다. 그러나 props
는 반드시 자신의 부모 컴포넌트로부터 전달받아야한다는 명확한 한계가 있다.
부모로 부터 props를 전달받는 과정이 depth가 하나라면 괜찮지만, 상위 컴포넌트로부터 데이터를 내려받는 depth가 깊어진다고 가정해보자.
A -> B -> C -> D
로 props를 전달하는 구조에서는 D에서 사용하기 위해 B, C 컴포넌트에서 사용하지 않는 props를 전달해줘야한다는 문제점이 있다.
프로젝트 규모가 커지고 컴포넌트들이 많아질 수록 문제는 커진다. 이러한 문제점을 해결하기 위해 context api를 사용할 수 있다.
프로젝트 어딘가에 context라는 상자 하나를 만든다고 생각하자.
그 상자 안에는 다른 컴포넌트에 전달하고 싶은 값을 넣어둔다.
이 값이 필요한 컴포넌트에 context 상자를 연결하면 그 순간부터 해당 컴포넌트 하위에 있는 컴포넌트들은 context 상자 데이터에 접근할 권한을 얻게 되는 것이다.
그래서 리액트의 최상위 컴포넌트인 App에서 context와 연결한다면 프로젝트 내의 모든 컴포넌트에서 context 내부의 데이터에 접근할 수 있게 되는 것이다.
간단한 코드와 함께 보면 이해가 쉽다.
createContext를 통해 과일의 이름과 가격을 담는 context를 만든다.
store/fruits.js
import React, { createContext } from "react";
export const FruitsContext = createContext();
const FruitsStore = (props) => {
const fruits = {
name: "orange",
price: 1000
};
return (
<FruitsContext.Provider value={fruits}>
{props.children}
</FruitsContext.Provider>
);
};
export default FruitsStore;
최상위 컴포넌트인 App에서 사용하고자 하는 FruitsStore로 감싸주면 이제 하위의 컴포넌트에서 FruitsStore 내부의 fruits 데이터에 접근할 수 있는 것이다.
App.js
<FruitsStore>
<Router>
<Switch>
<Route exact path="/" component={Name} />
<Route exact path="/price" component={Price} />
</Switch>
</Router>
</FruitsStore>
Name.js
import React, { useContext } from "react";
import { FruitsContext } from "../store/fruits";
const Name = () => {
const context = useContext(FruitsContext);
console.log(context);
return (
<div>
<span>{context.name}</span>
</div>
);
};
export default Name;
만약, FruitsStore가 Name컴포넌트만 감싸게 된다면 어떻게 될까?
Price.js
import React, { useContext } from "react";
import { FruitsContext } from "../store/fruits";
const Price = () => {
const context = useContext(FruitsContext);
console.log(context); //undefined
return (
<div>
<span>{context.price}</span>
</div>
);
};
export default Price;
undefined가 된다.
Provider로 감싸져 있는 하위 컴포넌트 들에서만 값에 접근이 가능하다.