리액트 컴포넌트들은 관련된 state와 함수들을 자식컴포넌트로 넘겨주는 구조가 많다. 그러다보면 애플리케이션 안의 여러 컴포넌트들에 전해줘야 하는 props의 경우 필요한 컴포넌트로 전달하기위해 중간다리 역할을 하는 컴포넌트가 생기기도 한다.
예를 들어 다음 UseList 컴포넌트를 App.js컴포넌트에서 불러와 하위 User컴포넌트와 연결되는 구조라고 가정할때 App.js에서 선언된 user, onRemove, onToggle 을 UserList에서는 전달역할만 하고있을뿐 직접 사용하고있지 않다.
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
간단한 구조에서는 별문제가 되지 않겠지만 복잡한 구조로 발전되다보면 개발과 코드해석이 힘든 구조가 될것이다.
이럴때, 리액트의 Context API 와 이전 섹션에서 배웠던 dispatch 를 함께 사용하면 이러한 복잡한 구조를 해결 할 수 있다.
리액트의 Context API 를 사용하면, 프로젝트 안에서 전역적으로 사용 할 수 있는 값을 관리 할 수 있다. 이 값은 함수일수도 있고, 어떤 외부 라이브러리 인스턴스일수도 있고 심지어 DOM 일 수도 있다.
다음은 간단한 예제 코드이다.
import React, {createContext, useContext, useState} from 'react';
const MyContext = createContext('defaultValue')
function Child(){
const text = useContext(MyContext);
return <div>안녕하세요? {text}</div>
}
function Parent(){
return <Child />
}
function GrandParent(){
return <Parent/>
}
function ContextSample(){
const [value, setValue] = useState(true)
return (
<MyContext.Provider value={value ? 'GOOD' : 'BAD'}>
<GrandParent />
<button onClick={()=> setValue(!value)}>CLICK ME</button>
</MyContext.Provider>
)
}
export default ContextSample;
위코드는 중첩되어 불러와지는 컴포넌트를 표현하고있다. props를 전달하기위해 직접 값을 지정하는 대신 createContext와 useContext를 활용하여 상위 컴포넌트에서 최하단 컴포넌트로 쉽게 값을 전달하고 있다.
기본값 'defaultValue' 문자열을 선언해준후에 최상단 컴포넌트 ContextSample 에서 Provider 속성을 이용해 어디서든 값을 사용할수있도록 세팅해주었다. 이 값은 useState를 통해 변화시켜 전달도 가능하며 이번예제는 불리언값을 반전시켜 문자열을 토글시켜주는 간단한 기능을 구현해보았다.