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;
카운터가 작동하나요?