#Context

기존에는 컴포넌트의 props를 통해 부모에서 자식으로 단방향 데이터를 전송

Context : 컴포넌트 트리를 이용해 곧 바로 데이터를 전송하는 방식

즉, props를 통해 계속 원하는 단계까지 보내는 것이 아닌
데이터를 Context에 담아두었다가 원하는 단계로 바로 꺼내주는 것


언제 Context를 사용해야 할까?
여러 개의 Component들이 접근해야 하는 데이터
- 로그인 여부, 로그인 정보, UI테마, 현재 언어등...


기존 코드

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

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

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

App에서 테마를 입력하고, Toolbar컴포넌트가 props로 받아 다시 ThemedButton컴포넌트로 전달후
ThemedButton이 버튼의 속성을 받는다


Context 사용

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

// 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={props.theme}/>}
    </ThemeContext.Consumer>  
  );  
} 

# Consumer의 역할.feat(chatGPT)

.Consumer는 React 컨텍스트(Context)의 값을 소비(consume)하고 해당 값에 접근하는 데 사용되는 React 컴포넌트입니다.

React 컨텍스트는 데이터를 상위 컴포넌트에서 하위 컴포넌트로 효율적으로 전달하는 데 사용됩니다. .Consumer 컴포넌트는 이러한 데이터를 소비하고 하위 컴포넌트에서 해당 데이터에 접근할 수 있게 해줍니다.

.Consumer는 다음과 같은 패턴으로 사용됩니다:

<SomeContext.Consumer>
  {contextValue => (
    // contextValue를 사용하여 원하는 작업 수행
  )}
</SomeContext.Consumer>
  • <SomeContext.Consumer>: 컨텍스트를 소비하는 데 사용되는 컴포넌트입니다. SomeContext는 컨텍스트 객체입니다.
  • {contextValue => ...}: 콜백 함수로, 컨텍스트의 값을 매개변수로 받아와서 사용합니다. 이 부분에서 원하는 동작을 수행할 수 있습니다.

예를 들어, 이전 코드에서 ThemedButton 컴포넌트는 ThemeContext.Consumer를 사용하여 value를 가져와서 그 값을 사용하여 버튼을 렌더링하고 있습니다. 이로써 ThemedButton은 상위 컴포넌트에서 제공한 테마 정보를 사용할 수 있게 되는 것입니다.


Context 사용 시 고려사항
- 재사용성이 떨어진다

//Page컴폰넌트는 PageLayout컴포넌트를 렌더링
<Page user={user} avatarSize={avatarSize} />

//PageLayout컴포넌트는 NavigationBar컴포넌트를 렌더링
<PageLayout user={user} avatarSize={avatarSize} />

//NavigationBar컴포넌트는 Link컴포넌트를 렌더링
<NavigationBar user={user} avatarSize={avatarSize} />

//Page컴폰넌트는 PageLayout컴포넌트를 렌더링
<Link href={user.permalink}>
    <Avatar user={user} size={avatarSize} />
</Link>

Avatar 컴포넌트를 변수에 저장하여 직접 넘기기

function Page(props) {
  const user = props.user;
 
  const userLink = ( // 맨 밑에 있던 컴포넌트 전체를 변수에 저장
    <Link href={user.permalink}>
        <Avatar user={user} size={avatarSize} />
    </Link>
  );
 
  // Page 컴포넌트는 PageLayout 컴포넌트를 렌더링
  // 이때 props로 userLink를 함께 전달
  return <PageLayout userLink={userLink} />; // 컴포넌트 전체를 넣은 변수를 다른 컴포넌트에게 전달
}

// PageLayout 컴포넌트는 NavigationBar 컴포넌트를 랜더링
<PageLayout userLink={...}/>

// NavigationBar 컴포넌트는 props로 전달받은 userLink element를 리턴
<NavigationBar userLink={...}/>

가장 상위만 정보를 가지고 있으면 된다
또한, 최상위 컴포넌트에게 더 많은 권한이 부여됨
하지만 데이터가 많아질 수록 상위 컴포넌트는 복잡해짐


topBar와 content변수에 하위컴포넌트를 분할해서 넣었다

function Page(props) {
  const user = props.user;
 
  const topBar = (
    <NavigationBar>
      <Link href={user.permalink}>
        <Avatar user={user} size={props.avatarSize}/>
      </Link>
    </NavigationBar>
  );
  const content = <Feed user={user} />;
 
  return (
    <PageLayout
      topBar={topBar}
      content={content}
    />
  );
}

하위 컴포넌트의 의존성을 상위 컴포넌트와 분리시킬때 사용
but, 하나의 데이터에 여러 중첩된 컴포넌트가 접근이 필요할 때는 Context를 사용해야 한다(지역정보, UI테마, 캐싱된 데이터)

profile
페라리 타는 백엔드 개발자

0개의 댓글