처음 만난 리액트 문서


14.2 언제 Context를 사용해야 할까?

Context를 사용하면 어떤 컴포넌트든지 데이터에 쉽게 접근할 수 있다고 했는데, 그렇다면 언제 Context를 사용하면 좋을까요? 먼저 여러 개의 컴포넌트들이 접근해야하는 데이터는 어떤 것들이 있는지 알아보도록 하겠습니다.

여러 컴포넌트에서 자주 필요로 하는 데이터로는 사용자의 로그인 여부, 로그인 정보, UI 테마, 현재 선택된 언어 등이 있을 수 있습니다. 예를 들어 웹사이트 상단에 위치한 내비게이션 바(Navigation Bar)에 사용자의 로그인 여부에 따라서 로그인 버튼과 로그아웃 버튼을 선택적으로 보여주고 싶은 경우, 현재 로그인 상태 데이터에 접근을 할 필요가 있겠죠. 마찬가지로 UI 테마, 현재 선택된 언어 같은 데이터들도 곳곳에 있는 컴포넌트들에서 접근이 자주 일어날 가능성이 높은 데이터입니다.

이러한 데이터들을 기존 방식대로 컴포넌트의 props를 통해서 넘겨주게 되면 자식 컴포넌트의 자식 컴포넌트까지 계속해서 타고 내려갈 수 밖에 없게 됩니다. 아래 코드는 현재 선택된 테마를 기존의 방식을 사용하여 컴포넌트의 props로 전달하는 예시 코드입니다.

function App(props) {
    return <Toolbar theme="dark" />;
}

function Toolbar(props) {
    // 이 Toolbar 컴포넌트는 ThemedButton에 theme를 넘겨주기 위해서 'theme' prop을 가져야만 합니다.
    // 현재 테마를 알아야 하는 모든 버튼에 대해서 props로 전달하는 것은 굉장히 비효율적입니다.
    return (
        <div>
            <ThemedButton theme={props.theme} />
        </div>
    );
}

function ThemedButton(props) {
    return <Button theme={props.theme} />;
}

위 코드에서는 총 세 개의 컴포넌트가 나옵니다. 먼저 가장 상위 컴포넌트인 App컴포넌트에서는 Toolbar컴포넌트를 사용하고 있습니다. 이 때 theme이라는 이름의 prop으로 현재 테마인 dark를 넘깁니다. 그리고 Toolbar컴포넌트에서는 ThemedButton컴포넌트를 사용하는데, ThemedButton컴포넌트에서 현재 테마를 필요로 합니다. 그래서 prop으로 받은 theme을 하위 컴포넌트인 ThemedButton컴포넌트에 전달합니다. 그리고 최종적으로 ThemedButton컴포넌트에서는 props.theme으로 데이터에 접근하여 버튼에 어두운 테마를 입히게 됩니다.

위에서 살펴본 것처럼 props를 통해서 데이터를 전달하는 기존 방식은 실제 데이터를 필요로 하는 컴포넌트까지의 깊이가 깊어질수록 복잡해집니다. 반복적인 코드를 계속해서 작성해주어야 하기 때문에 비효율적이고 직관적이지도 않습니다. Context를 사용하면 이러한 방식을 깔끔하게 개선할 수 있습니다. 아래 코드는 Context를 사용하여 위와 동일한 기능을 구현한 것입니다.

// Context는 데이터를 매번 컴포넌트를 통해 전달할 필요없이 component tree로 곧바로 전달하게 해줍니다.
// 여기에서는 현재 테마를 위한 context를 생성하며, 기본값은 'light' 입니다.
const ThemeContext = React.createContext('light');

// Provider를 사용하여 하위 컴포넌트들에게 현재 테마 데이터를 전달합니다.
// 모든 하위 컴포넌트들은 컴포넌트 트리 하단에 얼마나 깊이 있는지에 관계없이 데이터를 읽을 수 있습니다.
// 여기에서는 현재 테마값으로 'dark'를 전달하고 있습니다.
function App(props) {
    return (
        <ThemeContext.Provider value="dark">
            <Toolbar />
        </ThemeContext.Provider>
    );
}

// 이제 중간에 위치한 컴포넌트는 테마 데이터를 하위 컴포넌트로 전달할 필요가 없습니다.
function Toolbar(props) {
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

function ThemedButton(props) {
    // 리액트는 가장 가까운 상위 테마 Provider를 찾아서 해당되는 값을 사용합니다.
    // 만약 해당되는 Provider가 없을 경우 기본값(여기서는 'light')을 사용합니다.
    // 여기에서는 상위 Provider가 있기 때문에 현재 테마의 값은 'dark'가 됩니다.
    return (
        <ThemeContext.Consumer>
            {value => <Button theme={value} />}
        </ThemeContext.Consumer>
    );
}

위 코드에서는 먼저 React.createContext()함수를 사용해서 ThemeContext라는 이름의 Context를 하나 생성했습니다. 그리고 Context를 사용할 컴포넌트의 상위 컴포넌트에서 Provider로 감싸주어야 하는데, 여기에서는 최상위 컴포넌트인 App컴포넌트를 ThemeContext.Provider로 감싸주었습니다. 이렇게 하면 Provider의 모든 하위 컴포넌트들은 얼마나 깊이 위치해 있는지에 관계없이 Context의 데이터를 읽을 수 있습니다. Context를 사용한 코드를 보면 전체적으로 코드도 깔끔해지고 직관적으로 바뀐 것을 볼 수 있습니다. 이처럼 여러 컴포넌트에서 계속해서 접근이 일어날 수 있는 데이터들이 있는 경우에는 Context를 사용하는 것이 좋습니다.


마지막 업데이트: 2025년 08월 28일 08시 53분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page