상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때, 속성값이 사용되는데 가까운 거리에 있는 몇 개의 하위 컴포넌트로 전달할 때는 속성값으로 충분하다.
하지만, 부모 컴포넌트와 가장 말단에 있는 컴포넌트 사이에 수천개의 컴포넌트가 있는 경우, 속성값을 내려주는 코드를 반복적으로 작성해야 하는 문제가 발생할 수 있다.
import React from 'react';
function App() {
return (
<div>
<div>상단메뉴</div>
<Profile username="mike"/>
<div>하단메뉴</div>
</div>
);
}
function Profile({username}) {
return(
<div>
<Greeting username={username}/>
</div>
)
}
function Greeting ({username}) {
return(
<p>{`${username}님 안녕하세요!`}</p>
)
}
🚩 이때, 전역적으로 상태를 관리하는 라이브러리를 사용하거나,
React
에 내장되어 있는 context API를 사용하면, 컴포넌트의 중첩 구조가 복잡한 경우에도 손쉽게 데이터를 전달할 수 있다. 위의 코드를 context API를 사용해서 고칠 수 있다.
import React from 'react';
const UserContext = createContext('');
function App() {
return (
<div>
<UserContext.Provider value="mike">
<div>상단메뉴</div>
<Profile username="mike" />
<div>하단메뉴</div>
</UserContext.Provider>
</div>
);
}
function Profile() {
return (
<div>
<Greeting />
</div>
);
}
function Greeting() {
return (
<UserContext.Consumer>
<p>{`${username}님 안녕하세요!`}</p>
</UserContext.Consumer>
);
}
createContext 함수를 호출하면 context 객체가 생성된다.
createContext 함수의 구조는 다음과 같다.
createContext(defaultValue) => {Provider, Consumer}
Provider 컴포넌트의 속성값이 변경되면 하위의 모든 Consumer 컴포넌트는 다시 렌더링된다.
import React, {useState} from 'react';
const UserContext = createContext('');
function App() {
const [username, setUsername] = useState("");
return (
<div>
<UserContext.Provider value={username}>
<Profile/>
</UserContext.Provider>
<input type="text" value={username} onChange={e => setUsername(e.target.value)}
</div>
);
}
const Profile = React.memo(() => {
return(
<div>
<Greeting/>
</div>
)
})
function Greeting() {
return (
<UserContext.Consumer>
<p>{`${username}님 안녕하세요!`}</p>
</UserContext.Consumer>
);
}
1. username의 state가 변경되면 App 컴포넌트는 리렌더링된다.
2. Profile 컴포넌트는 React.memo로 만들어졌고, 리렌더를 유발하는 속성값이 없기 때문에 최초 한 번만 렌더링된다.
3. Profile 컴포넌트의 렌더링 여부와 상관 없이 Greeting 컴포넌트의 Consumer 컴포넌트는 다시 렌더링된다.
즉,
중간
컴포넌트( Profile )
의 렌더링 여부와 상관 없이Provider
컴포넌트로 새로운 데이터가 입력되면,Consumer
컴포넌트가 다시 렌더링되는 것이 보장된다.