Context 가 여러개일땐?

이전에, Context 를 여러개 만들 수도 있다고 말씀드렸었지요? 실제로 여러개를 사용한다면 어떤 형식으로 사용할까요? 한번 또 다른 Context 를 만들어봅시다!

src/contexts/another.js

import React, { Component, createContext } from 'react';

const Context = createContext();

const {
  Provider,
  Consumer: AnotherConsumer
} = Context;

class AnotherProvider extends Component {
  state = {
    number: 1,
  }
  actions = {
    increment: () => {
      this.setState(
        ({ number }) => ({ number: number + 1 })
      );
    }
  }
  render() {
    const { state, actions } = this;
    const value = { state, actions };
    return (
      <Provider value={value}>
        {this.props.children}
      </Provider>
    );
  }
}

function useAnother(WrappedComponent) {
  return function UseAnother(props) {
    return (
      <AnotherConsumer>
        {
          ({ state, actions }) => (
            <WrappedComponent
              number={state.number}
              increment={actions.increment}
            />
          )
        }
      </AnotherConsumer>
    )
  }
}

export {
  AnotherProvider,
  AnotherConsumer,
  useAnother
};

그럼, 이걸 기반으로 카운터 컴포넌트를 만들어볼까요? 우선, App 에서 또 Provider 를 넣어줘야 하는데.. 그렇게 하면 새로운 Context 만들때마다 다음과 같은 형식으로 계속 깊어지는게 맘에들지 않을 수도 있습니다.

return (
  <SampleProvider>
    <AnotherProvider>
      ....
    </AnotherProvider>
  </SampleProvider>
)

배열의 내장함수 reduce 와 리액트 컴포넌트의 createElement 를 활용하여 다음 코드를 작성해보세요.

src/App.js

import React from 'react';
import LeftPane from './components/LeftPane';
import RightPane from './components/RightPane';
import { SampleProvider } from './contexts/sample';
import { AnotherProvider } from './contexts/another';

const AppProvider = ({ contexts, children }) => contexts.reduce(
  (prev, context) => React.createElement(context, {
    children: prev
  }), 
  children
);

const App = () => {
  return (
    <AppProvider
      contexts={[SampleProvider, AnotherProvider]}
    >
      <div className="panes">
        <LeftPane />
        <RightPane />
      </div>
    </AppProvider>
  );
};

export default App;

이렇게 하면, Context 갯수가 많아져도, Provider를 적용하기 위해서 코드의 구조가 깊어질 필요가 없답니다. contexts 를 props 로 전달만 해주면 되죠.

자, 그럼 방금 만든 Context 를 사용해서 Counter 컴포넌트를 구현해봅시다!

src/components/Counter.js

import React from 'react';
import { useAnother } from '../contexts/another';

const Counter = ({ number, increment}) => {
  return (
    <div>
      <h1>{number}</h1>
      <button onClick={increment}>더하기</button>
    </div>
  );
};

export default useAnother(Counter);

다음, App 에서 렌더링해보세요.

src/App.js

import React from 'react';
import LeftPane from './components/LeftPane';
import RightPane from './components/RightPane';
import { SampleProvider } from './contexts/sample';
import { AnotherProvider } from './contexts/another';
import Counter from './components/Counter';

const AppProvider = ({ contexts, children }) => contexts.reduce(
  (prev, context) => React.createElement(context, {
    children: prev
  }), 
  children
);

const App = () => {
  return (
    <AppProvider
      contexts={[SampleProvider, AnotherProvider]}
    >
      <div className="panes">
        <LeftPane />
        <RightPane />
      </div>
      <Counter />
    </AppProvider>
  );
};

export default App;

카운터가 작동하나요?

results matching ""

    No results matching ""