React에서 컴포넌트를 작성하는 방법은 두 가지가 있다. 하나는 함수형 컴포넌트이고 다른 하나는 클래스형 컴포넌트 이다. 책이나 강의를 보더라도 예전에는 전부 클래스형 컴포넌트로 작성했지만 Hook의 출현과 비슷한 시기부터 함수형 컴포넌트를 많이 사용하는 것을 알 수 있다. 무슨 차이가 있는 것일까? 알아보자
가장 명확하면서도 확실한 차이는 구문의 차이이다. 이름에서도 알 수 있듯 함수형 컴포넌트는 일반적인 자바스크립트의 함수의 형태이다 ( JSX를 리턴하는 ) 이에 비해 클래스형 컴포넌트는 render 메서드를 갖고 있는 React.Component
를 상속받아 사용하고 있다.
import React from "react";
const FunctionalComponent = () = >{
return <h1> Hi There! </h1>;
};
혹은
function FunctionalComponent(){
return <h1> Hi There ! </h1>;
};
위의 코드에서 알 수 있듯 함수형 컴포넌트는 JSX를 반환하는 자바스크립트 함수이다.
import React , { Component } from "react";
class ClassComponent extends Component{
render(){
return <h1> Hi There! </h1>;
}
}
혹은
class ClassComponent extends React.Component{
render(){
return <h1> Hi There! </h1>;
}
}
클래스형 컴포넌트의 경우React.Component
를 불러와서 상속받아서 사용해야 한다. JSX는 render 메서드 내부에서 반환된다.
아래와 같이 하위 컴포넌트에 name : "wook"
이라는 props를 전달해 보자.
<Component name ="wook" />
const FunctionalComponent = (props) =>{
return <h1> Hello, {props.name} </h1>;
};
혹은
const FunctionalComponent = ({name}) =>{
return <h1> Hello, {name} </h1>;
};
함수형 컴포넌트의 경우 함수의 인자로 props를 전달받는 방식을 사용한다.
class ClassComponent extends React.Component{
render() {
const { name } = this.props;
return <h1>Hello, { name } </h1>;
}
}
클래스형 컴포넌트의 경우 this
키워드를 사용하여 props를 조회할 수 있다. ( this.props.name
으로도 접근이 가능하다. )
아마도 가장 중요한 이유가 아닐까 한다. 비교적 최근 까지 (라고 해도 약 2019년) 클래스형 컴포넌트에서만 상태(state)를 관리할 수 있었다. 그러나 React 16.8부터 React Hook 이 도입되었고 개발자들은 stateful 한 함수형 컴포넌트를 작성할 수 있게 되었다.
const FunctionalComponent = () => {
const [count , setCount] = React.useState(0);
return (
<div>
<p> count : {count} </p>
<button onClick = {() => setCount(count+1)}>Click</button>
</div>
);
};
함수형 컴포넌트에서 상태 변수를 사용하기 위해서는 useState
라는 Hook을 사용해야 한다.
위의 예제는 버튼을 클릭할 때 마다 count라는 상태에 1을 더해주는 함수형 컴포넌트이다.
(위의 예제에서 인자로 0을 넣어주었기 때문에 초기값이 0이 된다.)
class ClassComponent extends React.Component{
constructor(props){
super(props);
this.state = {
count : 0
};
}
render(){
return(
<div>
<p> count : {count} </p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click
</button>
</div>
);
}//end of render
}//end of class
클래스형 컴포넌트의 경우 함수형 컴포넌트와 기본적으로 아이디어는 같지만 , 조금의 차이가 있다. 먼저 constructor
에 대해 알아보자.
“The constructor for a React component is called before it is mounted. When implementing the constructor for a React.Component subclass, you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs.”
기본적으로 생성자에서 super(props)
를 호출하지 않으면 모든 상태 변수들은 전부 undefined가 된다. 그렇기 때문에 개발자는 생성자를 먼저 선언하고 생성자 내부에 key 와 value로 이루어진 상태 객체를 생성해야 한다.
그래야만 JSX 구문 내부에서 this.state.count
와 같은 형식으로 상태 변수에 접근이 가능하다.
생명주기는 컴포넌트의 렌더링 시기와 관련하여 중요한 역할을 한다.
클래스형 컴포넌트에서 함수형 컴포넌트로 이사하는 과정에서 componentDidMount()
같은 메서드가 어떻게 대체되는지 알아보자.
componentDidMount()
메서드는 첫 번째 렌더링이 완료된 직후에 호출된다.
<< 클래스형 컴포넌트 >>
class ClassComponent extends React.Component {
componentDidMount() {
console.log("Hello");
}
render() {
return <h1>Hello, World</h1>;
}
}
위의 클래스형 컴포넌트를 Hook을 사용한 함수형 컴포넌트로 바꿔보자
<< 함수형 컴포넌트 >>
const FunctionalComponent = () => {
React.useEffect(()=>{
console.log("Hello");
}, []);
return <h1>Hello , World</h1>;
};
함수형 컴포넌트에서 componentDidMount
를 대체하기 위해서는 useEffect
라는 hook을 사용하면 된다. useEffect
의 두 번째 인자에 있는 배열은 해당 배열에 있는 state의 값이 변경될때 useEffect를 실행해라 라는 용도로 사용되는데, 이렇게 빈 배열을 두면 컴포넌트가 마운트 될 때 한번만 호출된다.
만약 어떠한 사유로 인해 컴포넌트가 unmounting 된다면 해당 컴포넌트에 달려있는 이벤트도 전부 지워야 한다. 그렇지 않으면 큰 프로젝트의 경우 메모리 누수를 야기할 수 있다.
<< 클래스형 컴포넌트 >>
class ClassComponent extends React.Component {
componentWillUnmount() {
console.log("Bye");
}
render() {
return <h1>Bye, World</h1>;
}
}
위의 코드를 hook을 사용한 함수형 컴포넌트로 변경해 보자.
<< 함수형 컴포넌트 >>
const FunctionalComponent = () => {
React.useEffect(() => {
return () => {
console.log("Bye");
};
}, []);
return <h1>Bye, World</h1>;
};
이렇게 useEffect
를 사용하여 관리하면 한 가지 좋은점이 있는데 바로 mounting 과 unmounting 되는 경우를 한 곳에서 처리할 수 있게 된다.
(+ 이외의 다른 생명주기 함수들도 hook으로 처리가 가능하다.)
출처 에 있는 글을 직접 번역
잘못된 지식이나 오타 , 수정사항 있으면 알려주시면 감사하겠습니다.