[React]_Context

안승찬·2023년 7월 24일

React

목록 보기
6/9

context

context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있습니다.
일반적인 React 애플리케이션에서 데이터는 위에서 아래로 props를 통해 전달 되지만, 애플리케이션 안의 여러 컴포넌트들에 전해줘야하는 props의 경우 이 과정이 번거로울 수 있습니다. context를 이용하면, 트리 단계마다 명시적으로 props를 넘겨주지 않아도 많은 컴포넌트가 값을 공유하게 할 수 있습니다.

그럼 언제 context를 써야 해?

context는 React 컴포넌트 트리 안에서 전역적이라고 볼 수 있는 데이터를 공유 할 수 있도록 고안된 방법입니다. 그러한 데이터로는 현재 로그인한 유저,테마,선호하는 언어 등이 있습니다.

예시코드
최종 선택은 dark테마 입니다.

 
 const ThemeContext = React.createContext('light');


	class App extends React.Component {
      render() {
     	return (
           <ThemeContext.Provider value="dark">
	        <Toolbar />
      </ThemeContext.Provider>
        )
      }
    }
    
    function Toolbar(props){     
      return(
         <div>
      <ThemedButton />
	    </div>
        )
    }

class ThemedButton extends React.Component {
   static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }      
      

API

React.createContext

	const MyContext = React.createContext(defaultValue);

Context 객체를 만듭니다. Context 객체를 구독하고 있는 컴포넌트를 렌더링 할 때 React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재값을 읽습니다.

Context.Provider

	<MyContext.Provider value={/}/>

Context 오브젝트에 포함된 React 컴포넌트인 Provider는 context를 구독하는 컴포넌트에게 context의 변화를 알리는 역할을 합니다. Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달합니다. Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop가 바뀔 때마다 다시 렌더링 됩니다.

Context.Consumer

<MyContext.Consumer>
  {value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>

이 컴포넌트를 사용하면 함수 컴포넌트안에서 context를 구독할 수 있습니다.
Context.Consumer의 자식은 함수여야합니다. 이 함수는 context의 현재값을 받고 React 노드를 반환합니다. 이 함수가 받는 value 매개변수 값은 해당 context의 Provider 중 상위 트리에서 가장 가까운 Provider의 vlaue prop과 동일합니다. 상위에 Provider가 없다면 value 매개변수 값은 createContext()에 보냈던 defaultValue와 동일할 것입니다.

Context.displayName

Context 객체는 displayName 문자열 속성을 설정할 수 있습니다.

const MyContext = React.createContext()
MyContext.displayName = "MyDisplayName";
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> //"MyDisplayName.Consumer" in DevTools

값이 변하는 context 예시


//theme-context.js

export const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222',
  },
};

export const ThemeContext = React.createContext(
  themes.dark // 기본값
);

//themed-button.js
import {ThemeContext} from "./theme-context";

class ThemedButton extends React.Component {
	render(){
      let props = this.props;
      let theme = this.context;
    }
  return(
  	<button 
     {...props}
     style={{backgroundColor: theme.background}	
     />  
  )       
}

ThemedButton.contextType = ThemeContext;

export default ThemedButton;


//app.js
import {ThemeContext, themes} from './theme-context';

import ThemedButton from './themed-button';


function Toolbar(props) {
  return (
    <ThemedButton onClick={props.changeTheme}>
      Change Theme
    </ThemedButton>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: themes.light,
    };

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };
  
   render() {
    // ThemeProvider 안에 있는 ThemedButton은 state로부터 theme 값을 읽지만
    // Provider 밖에 있는 ThemedButton는 기본값인 dark를 사용합니다.
    return (
      <Page>
        <ThemeContext.Provider value={this.state.theme}>
          <Toolbar changeTheme={this.toggleTheme} />
        </ThemeContext.Provider>
        <Section>
          <ThemedButton />
        </Section>
      </Page>
    );
  }
}}

하위 컴포넌트에서 context 업데이트 하기


//theme-context.js

export const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => {},
});


//theme-toggler-button.js
import {ThemeContext} from './theme-context';

function ThemeTogglerButton() {
  // ThemeTogglerButton는 context로부터
  // theme 값과 함께 toggleTheme 매서드도 받고 있습니다.
  return (
    <ThemeContext.Consumer>
      {({theme, toggleTheme}) => (
        <button
          onClick={toggleTheme}
          style={{backgroundColor: theme.background}}>
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

export default ThemeTogglerButton;

//app.js

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    // state에 업데이트 메서드도 포함되어있으므로
    // 이 또한 context Provider를 통해 전달될것입니다.
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }

  render() {
    // Provider에 state 전체를 넘겨줍니다.
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

function Content() {
  return (
    <div>
      <ThemeTogglerButton />
    </div>
  );
}

const root = ReactDOM.createRoot(
  document.getElementById('root')
);
root.render(<App />);

1개의 댓글

comment-user-thumbnail
2023년 7월 24일

많은 도움이 되었습니다, 감사합니다.

답글 달기