티스토리 뷰

Vue&React

Context API

U_pic 2022. 4. 27. 02:37

React에서 데이터는 일반적으로 위에서 아래(부모 컴포넌트 → 자식 컴포넌트)로 props를 통해 전달된다.

하지만 프로덕트의 크기가 커지고, 컴포넌트의 깊이가 깊어지면 Props의 사용이 번거롭게 느껴진다.

Context를 활용하면 컴포넌트 사이에 이러한 값을 props 전달없이 공유할 수 있다.

언제 Context를 사용해야 할까

Context는 컴포넌트 트리 안에서 전역적으로 데이터를 공유할 수 있도록 고안한 방법이다.

현재 로그인 상태, 테마, 현재 사용중인 언어 이러한 데이터를 자주 사용한다.

// context를 사용하면 모든 컴포넌트를 일일이 통하지 않고도
// 원하는 값을 컴포넌트 트리 깊숙한 곳까지 보낼 수 있습니다.
// light를 기본값으로 하는 테마 context를 만들어 봅시다.
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // Provider를 이용해 하위 트리에 테마 값을 보내줍니다.
    // 아무리 깊숙히 있어도, 모든 컴포넌트가 이 값을 읽을 수 있습니다.
    // 아래 예시에서는 dark를 현재 선택된 테마 값으로 보내고 있습니다.
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 이젠 중간에 있는 컴포넌트가 일일이 테마를 넘겨줄 필요가 없습니다.
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 현재 선택된 테마 값을 읽기 위해 contextType을 지정합니다.
  // React는 가장 가까이 있는 테마 Provider를 찾아 그 값을 사용할 것입니다.
  // 이 예시에서 현재 선택된 테마는 dark입니다.
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

Context를 사용하기 전에 고려할 것

Context를 사용하는 가장 큰 이유로 Props를 많이 사용하게 될때 이 과정이 번거롭고, 코드가 복잡해보인다는 점을 꼽을 수 있다.

이 단점은 컴포넌트 자체를 Props로 넘겨 줌으로서 어느 정도 해소 가능한 부분이지만 완벽하게 문제를 해결할 수 있는 방법이 아닐 뿐더러, 코드라인이 더 복잡해질 수 도 있다.

데이터 값이 변할 때 마다 여러 레벨에 존재하는 컴포넌트에게 전달 해야할 때 Context를 사용하여 유연하게 동작하도록 할 수 있다.

API

React.createContext

const Context = React.createContext(defaultValue);

Context 객체를 만드는 코드. Context 값을 가지고 있는 컴포넌트를 랜더링할 때 React는 트리의 가장 상위에 있는 짝이 맞는 Provider로 부터 현재 값을 가져온다.

defaultValue는 Provider로 전달받은 값이 없을 때만 쓰인다.

Context.Provider

<MyContext.Provider value={}>

Provider 컴포넌트는 Value의 값을 받아서 하위에 존재하는 컴포넌트에게 값을 전달한다. 컴포넌트 수의 제한은 없다. 아래 다른 Provider 컴포넌트가 있을 경우에 Provider 값이 우선된다.

Class.contextType

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* MyContext의 값을 이용한 코드 */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* ... */
  }
}
MyClass.contextType = MyContext;

클래스의 contextType의 프로퍼티로 createContext로 만든 Context 객체를 넘겨주면, 컴포넌트의 lifecycle에서 this.context로 가장 가까운 Provider가 제공하는 값을 사용할 수 있다.

Context.Consumer

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

context 변화를 등록하는 React Component. Context.Consumer의 자식은 함수여야한다.

컴포넌트가 전달받는 value 값은 가장 가까운 Provider가 제공하는 값이다. 만약 그 값이 없다면 createContext()선언시 지정한 default와 동일한 값을 가진다.

Context.displayName

Context 객체는 displayName 문자열 속성을 설정할 수 있습니다. React 개발자 도구는 이 문자열을 사용해서 context를 어떻게 보여줄 지 결정합니다.

예를 들어, 아래 컴포넌트는 개발자 도구에 MyDisplayName로 표시됩니다.

주의

재랜더링 여부를 판단할때 그 값의 참조 여부를 판단한다.

경우에 따라 부모가 랜더링될 때마다 하위 컴포넌트 까지 불필요하게 재랜더링 되는 현상이 발생할 수 있다.

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

위 처럼 코드를 작성하게되면 value 내부 값이 바뀔 때마다 객체를 새롭게 생성되기 때문에 Provider로 부터 값을 받는 하위 컴포넌트 모두 재랜더링된다. 이를 방지하기 위해서는 값을 부모 컴포넌트에서 state로 관리하면 된다.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <MyContext.Provider value={this.state.value}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

'Vue&React' 카테고리의 다른 글

[React] Redux-Thunk로 비동기로직 처리하기  (0) 2022.05.16
[React] Modal with Portal  (0) 2022.05.10
Vuex - (2)  (0) 2022.04.26
Vuex - (1)  (0) 2022.04.26
[Vue.js] style scoped  (0) 2022.04.10
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함