프로퍼티와 state는 부모와 자식 컴포넌트간에 연결된 상태에서 공유되는 데이터 였습니다. 컨텍스트는 연결없이 데이터 공유를 할 수 있게 해줍니다. 그래서 보통 '데이터 공유 저장소'와 '데이터 전파' 를 담당한다고 이야기 합니다.
컴포넌트는 트리 구조 형태를 띠고 있습니다.
<HomePageComponent>
<TableComponent>
<RowAComponent>
</RowAComponent>
<RowBComponent>
</RowBComponent>
</TableComponent>
</HomePageComponent>
HomePageComponent에서 프로퍼티로 데이터를 보내면 RowA까지 단방향으로 데이터가 흐르면서 들어갑니다.
여기서 의문이 듭니다. 데이터는 잘 전송되고 있는데 컨텍스트란 것은 왜 필요한걸까요?
예를 들어 HomePageComponent에서 RowAComponent로 바로 데이터를 보내고자 할때 프로퍼티의 경우 Home > Table > RowA 과정으로 데이터가 전송 됩니다. 만약 중간에 해당 프로퍼티를 사용하지 않는다면? 전달 과정에 누락된다면? 올바르게 데이터가 전송되지 못합니다.
관찰자 패턴 : 데이터는 공급자가 관리하고 관찰자는 공급자를 구독하여 데이터를 얻는방식
서로의 역할이 분리 되며 공급자는 데이터보관, 데이터 변경, 소비자에게 데이터 공급 역할
관찰자(소비자)는 공급자를 구독하여 데이터를 소비하는 역할을 하게 됩니다.
아래 그림을 보면 Home(data) -> 공급자로 전달되고 공급자 -> 소비자 로 전달 됩니다 만약 data가 변경되면 공급자는 변경된 data를 소비자에게 전달합니다 이를 '컴포넌트 간의 자료 의존성이 없어졌다'고 합니다. 이러한 흐름을 만들어 주는 것이 컨텍스트 입니다.
공급자를 구현 하는 방법은 공급자 역할을 할 컴포넌트에 공급자의 자료형(childContextTypes)과 데이터 제공 함수(getChildContext())를 정의하면 됩니다. 단 함수형 컴포넌트로 공급자 구현할 수 없으므로 클래스형 으로 구현해야 됩니다.
//공급자 구현
//src\06\HomePageComponent.jsx
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Button from '../04/Button';
import ButtonWithContext from './ButtonWithContext';
// 소비자 입니다.
function RowAComponent() {
return <Button>버튼</Button>;
}
function RowBComponent() {
return <Button>버튼</Button>;
}
function RowCComponent() {
return <ButtonWithContext>버튼</ButtonWithContext>;
} //소비자 출력
function TableComponent() {
return (
<table>
<RowBComponent />
<RowCComponent />
</table>
);
}
class HomePageComponent extends PureComponent {
constructor(props) {
super(props);
this.state = { loading: false };
this.setLoading = this.setLoading.bind(this);
//콜백함수 bind(this) 하지 않으면 소비자에서 찾지를 못함.
this.toggleLoading = this.toggleLoading.bind(this);
}
getChildContext() {
//해당 함수를 통해 소비자가 데이터를 받게됨
return {
loading: this.state.loading,
setLoading: this.setLoading,
};
}
setLoading(loading) {
this.setLoading({ loading });
}
toggleLoading() {
this.setState(({ loading }) => ({ loading: !loading }));
}
render() {
return (
<div>
<TableComponent />
<Button onPress={this.toggleLoading}>상태변경</Button>
</div>
);
}
}
HomePageComponent.childContextTypes = {
loading: PropTypes.bool,
setLoading: PropTypes.func,
};
export default HomePageComponent;