React의 장점으로 앞서 언급되었던 Virtual DOM으로 인한 DOM 관리의 편리함 뿐만 아니라 Component 단위 작성을 통해 생산성과 유지 보수를 용이
하게 할 수 있는 장점도 존재한다.
여기서 Component
란 앱을 이루는 최소한의 단위로 UI를 독립적이고 재사용이 가능하게 해주는 목적을 가진 조각이라고 생각하면 쉽다.
리액트에서 이러한 컴포넌트를 작성하는 방법에는 2가지가 있다.
Class Component
와 Function Component
이 존재하는데 구성요소 차이를 위주로 알아볼 생각이다.
import React, { Component } from "react";
class ClassComponent extends Component {
render() {
return <h1>Hello, world</h1>;
}
}
class component를 정의하기 위해서 extends React.Component를 사용
해야 하며 렌더링 할 JSX는 render 메서드 내부
에 작성해야 한다.
import React from "react";
const FunctionalComponent = () => {
return <h1>Hello, world</h1>;
};
or
import React from "react";
function FunctionalComponent() {
return <h1>Hello, world</h1>;
}
반면에 Function Component는 렌더링 할 JSX를 반환해주기만
하면 된다.
다음과 같이 'jiseong'이라는 이름의 props를 전달한다고 가정해보자.
<Component name="jiseong" />
class ClassComponent extends React.Component {
render() {
const { name } = this.props;
return <h1>Hello, { name }</h1>;
}
}
Class Component는 props를 참조하기 위해 this를 사용
해야 한다.
const FunctionalComponent = (props) => {
return <h1>Hello, {props.name}</h1>;
};
or
비구조할당을 이용한
const FunctionalComponent = ({ name }) => {
return <h1>Hello, {name}</h1>;
};
함수의 argument로 전달하기 때문에 parameter를 이용
하여 props을 참조할 수 있다.
다음과 같이 버튼을 누르면 count가 증가되는 앱이 있다고 가정해보자.
class ClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>count: {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click
</button>
</div>
);
}
}
우선적으로, state 변수를 사용하기 위해 생성자 내부에서 state key 와 초기값으로 이루어진 state 객체를 생성한다. (여기서는 count라는 key값을 가진 state를 선언해주었다.)
여기서 생성자 내부에 super(props)를 가장 먼저 호출한 이유는 다음과 같다.
React.Component 서브 클래스에 대한 생성자를 구현할 때
super(props)
다른 명령문보다 먼저 호출 해야 한다. 그렇지 않으면 this.props는 생성자에서 정의되지 않아 버그가 발생할 수 있다고 한다.
JSX 내부에서 state key 값에 접근할 때 this.state.count
와 같은 방법을 사용하며 버튼을 클릭했을 때 state 값을 변경시켜야하는데 이 때, 직접적으로 변경하지 않고 setState 함수를 이용하여 변경
한다.
const FunctionalComponent = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);
};
Function Component에서는 state 변수를 사용하기 위해서 useState Hook
을 사용해야 한다.
useState
의 첫번째 값으로는 현재 상태를 나타내며 두번째 값으로는 이를 업데이트하는 함수를 반환한다. (여기서는 count라는 이름과 setCount라는 이름으로 지었다.)
그 후, 단순하게 count를 이용하여 현재 상태
를 가져오고 setCount을 통해 state를 업데이트
할 수 있다.
사실 초기의 Function Component에서는 State 변수를 다룰 수 없었는데 React 16.8 이후
useState
가 도입되면서 사용이 가능해진 것이다.
Lifecycle
은 렌더링 타이밍에서 중요한 역할을 한다.
다양한 Lifecycle methods
들이 존재하지만 그 중 componentDidMount 와 componentWillUnmount에 대해서 알아보자.
componentDidMount
은 첫 번째 렌더링이 완료된 직후에 호출되는 메서드이며
componentWillUnmount
은 컴포넌트가 소멸된 시점에 호출되는 메서드이다.
class ClassComponent extends React.Component {
componentDidMount() {
console.log("Hello");
}
componentWillUnmount() {
console.log("Bye");
}
render() {
return <h1>Hello, World</h1>;
}
}
const FunctionalComponent = () => {
React.useEffect(() => {
console.log("Hello");
return () => {
console.log("Bye");
};
}, []);
return <h1>Bye, World</h1>;
};
useEffect hook
의 두번째 argument로 []
을 지정 시 componentDidMount
를 완벽하게 대체할 수 있다. 즉, 첫 번째 렌더링이 완료된 직후에만 호출된다.
여기서 두번째 argument는 특정 state 값이 변경 시에 useEffect를 다시 호출하고 싶을 때 사용된다.
Function Component에서 componentWillUnmount
를 사용하기 위해서는 useEffect 내부에서 함수를 반환
하기만 하면 된다.
주로 clearInterval 함수와 같은 subscriptions을 해제하고 싶을 때 사용한다.
내가 느낀 function component의 장점으로는 'mount와 unmount가 되는 코드를 한 곳에서 작성할 수 있어 유지보수가 쉽고 class component보다 코드를 간결하게 작성할 수 있다.' 라고 생각된다.
그리고 추가적으로 상위 컴포넌트에서 하위 컴포넌트(클래스형 컴포넌트 일 때)에게 props를 전달해주며 하위 컴포넌트에서 해당 props를 setTimeout함수를 이용하여 사용할 일이 있다면 Props는 리액트에서 불변(immutable) 값 이지만 this는 변경 가능한 값(mutable)임을 염두해야 한다고 한다.
참조: https://codesandbox.io/s/pjqnl16lm7