앞에서 Redux를 공부하면서 React만 사용할 수 있는 상태관리 도구인 Context API에 대한 궁금증이 생겨서 이 글을 작성하게 되었다.
Context API와 Redux를 비교하면서 개념을 확실히 정리해보자
중앙 상태 관리를 위한 상태 관리 도구이다.
React에서 Props와 State는 부모 컴포넌트와 자식 컴포넌트 또는 한 컴포넌트 안에서 데이터를 다루기 위해 사용한다고 했다. 하지만, 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 데이터의 흐름과는 관계없이 전역적인 데이터를 다룰 때 필요한 것이다.
이를 위해서 React는 Flux라는 개념을 도입하고, 그에 맞는 Context API를 제공하기 시작했다.
Redux와는 달리,
Context API에서는 여러 저장소가 존재할 수 있으며, Context, Provider, Consumer로 나뉘어진다.
전역 상태가 저장되는 곳이다.
전역 데이터를 Context에 저장하고, Context안에는 Provider와 Consumer가 정의되어 있다.
다른 컴포넌트에서는 이를 활용하여 상태에 접근할 수 있다.
여러 개의 Context가 사용될 수 있고, 만약 단 하나의 Context만 존재한다면 성능상의 문제가 발생할 수 있으므로 주의해야 한다.
import React from 'react';
export default React.createContext(defaultValue);
React.createContext()
의 인자로 상태의 초기값이 들어간다. 즉, initState와 같은 기능을 한다.
defaultValue
는 적절한 Provider를 찾지 못했을 때, 사용되는 값이다.
만약, provider를 통해서 undefined를 보낸다고 해도 해당 context를 가진 컴포넌트는 provider를 읽지 못한다.
정의한 Context를 하위 컴포넌트에 전달하는 역할을 한다.
value
를 사용해야 한다.제공된 상태에 접근하기 위해서는 Provider의 하위 컴포넌트
에 포함되어 있어야 한다.
따라서 모든 컴포넌트
에 접근하는 상태를 제공하는 루트 컴포넌트가 필요하므로, index.js
또는 app.js
에서 Provider를 정의해야 하는 것을 지켜야 한다.
//React.createContext()객체
import UserContext from './userContext';
class App extends Component {
render(){
return(
<UserContext.Provider value={{
name :'',
age : 0
}}>
{/*여기서 전역상태에 접근가능*/}
</UserContext.Provider>
}
Context의 변화를 구독하는 컴포넌트이다.
<UserContext.Consumer>
{value => /* context값을 이용한 렌더링*/}
</UserContext.Consumer>
Context는 Cousumer 사이에 있는 처음의 객체
를 Context에 인자로 전달하기 때문에, 바로 JSX를 작성하는 것이 아니라 빈 객체를 작성한 뒤 JSX 객체
를 작성해야 한다.
import { createContext } from 'react';
const ProfileContext = createContext({ name : "seohee", age : 12});
export default ProfileContext;
context를 생성하면서 기본으로 프로필의 정보를 지정해주었다.
이후, consumer
를 사용하여 ProfileContext
안에 있는 정보를 조회할 수 있다.
import React from 'react';
import ProfileContext from '../Contexts/Profile';
const ProfileBox = () => {
return(
<ProfileContext.Consumer>
{(value)=> (
<div style={{width : "64px", height: "64px"}}>
<div> NAME : {value.name}</div>
<div> AGE : {value.age}</div>
</div>
)}
</ProfileContext>
);
}
export default ProfileBox;
최종적으로 App에서 이를 실행해주면 된다.
import React from 'react';
import ProfileBox from './ProfileBox';
const App = () =>{
return (
<div>
<ProfileBox/>
</div>
);
};
export default App;
App.js에 provider를 추가하여 ProfileBox의 이름과 나이를 변경할 수 있다,
import React from 'react';
import ProfileBox from './ProfileBox';
import ProfileContext from './Profile';
const App = () => {
return(
<ProfileContext.Provider value={{name : "SEOHEE", age: 24}}>
<div>
<ProfileBox/>
</div>
);
};
export default App;
context의 value에는 값이 아닌 함수도 사용이 가능하다.
import { createContext, useState } from 'react';
import React from 'react';
const ProfileContext = createContext({
state : { name : "seohee", age : 12},
actions : {
setName : () => {},
setAge : () => {},
}
});
const ProfileProvider = ({children}) => {
const [name, setName] = useState("SEOHEE");
const [age, setAge] = useState(24);
const value = {
state : { name,age},
actions : { setName, setAge}
};
return (
<ProfileContext.Provider value = {value}>
{children}
</ProfileContext.Provider>
);
};
const { Consumer : ProfileConsumer } = ProfileContext;
export { ProfileProvider, ProfileConsumer};
import React from 'react';
import { ProfileConsumer } from './Profile';
const ProfileBox = () => {
return (
<ProfileConsumer >
{({state}) => (
<div style={{width:'64px', height:'64px'}}>
<div> NAME : {value.name}</div>
<div> AGE : {value.age}</div>
</div>
)}
</ProfileConsumer>
)
};
export default ProfileBox;
예제를 살펴보았듯이 Redux와 Context API는 전역 상태 관리를 위한 도구라는 것을 알 수 있으며, Redux가 Context API를 가지고 만든 라이브러리라는 사실 또한 알아낼 수 있다.
하지만, Redux는 Context API와는 다르게 전역 상태 관리 외에도 다양한 기능을 제공한다.
해당 기능은 아래와 같다.👇
로컬 스토리지
에 상태를 영구적으로 저장하고, 시작할 때 다시 불러오기가 가능하다.버그 찾는데 용이
하다.TDD 스타일
로 구현할 수 잇다.재사용
하면서 UI를 변경할 수 있게 한다.즉, Redux가 부가 기능을 많이 제공되어지고 있기에 이러한 기능이 필요하지 않고, 오로지 전역 상태 관리
만을 필요로 한다면 Context API를 사용하면 된다.
📚 학습할 때, 참고한 자료 📚