모든 컴포넌트는 초기화 단계, 업데이트 단계, 소멸 단계를 거친다. 각 단계 속에서 호출되는 메서드를 생명 주기 메서드라고 한다.
class MyComponent extends React.Component {
state={
currentMovie: this.props.age < 10 ? '뽀로로' : '어벤져스',
}
}
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.dataPromise = requestData();
}
componentDidMount () {
this.dataPromise.then(data => this.setState({data}));
}
}
class MyComponent extends Component {
constructor(props) {
super(props);
this.onClickInc = this.onClickInc.bind(this);
}
...
render() {
return (
<button onClick={this.onClickInc} />
)
}
}
클래스형 컴포넌트의 contextType 정적 멤버 변수에 컨텍스트 객체를 입력하면 클래스 내부에서 컨텍스트 데이터에 접근할 수 있다.
const ThemeContext = React.createContext('dark');
class MyComponent extends React.Component {
componentDidMount() {
const theme = this.context;
...
}
...
}
MyComponent.contextType = ThemeContext;
클래스형 컴포넌트에서는 훅 대신 고차 컴포넌트와 렌더 속성값 패턴으로 공통 기능을 관리할 수 있다.
//마운트 여부를 알려 주는 고차 컴포넌트
function withHasMounted(InputComponent) {
return class OutputComponent extends React.Component {
state = {
hasMounted: false;
}
componentDidMount() {
this.setState({hasMounted: true})
}
render() {
const {hasMounted} = this.state;
return <InputComponent {...this.props} hasMounted={hasMounted} />;
}
};
}
//마우스의 위치 정보를 알려 주는 렌더 속성값
//MouseTracer.tsx
class MouseTracer extends React.Component {
state = {
x: null,
y: null,
}
onMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY,
})
}
render () {
const {children} = this.props;
const {x, y} = this.state;
return <div onMouseMove={this.onMouseMove}>{children({x, y})}</div>;
}
}
훅은 기존 클래스형 컴포넌트의 여러가지 문제를 해결해주기 때문에 훅을 사용해 함수형 컴포넌트로 작성하는게 좋다.
function useOnUpdate(func) {
const isMountedRef = useRef(false);
useEffect(() => {
if (isMountedRef.current) {
func();
} else {
isMountedRef.current = true;
}
})
}
function MyComponent () {
const [_, forceUpdate] = useReducer(s => s + 1, 0);
function onClick() {
forceUpdate();
}
...
}
커스텀 훅을 감싸는 래퍼 컴포넌트(고차 컴포넌트 또는 렌더 속성값으로 구현)를 만들면 클래스형 컴포넌트에서도 커스텀 훅의 로직을 재사용할 수 있다.