프론트엔드 첫걸음

함수형 컴포넌트 class 컴포넌트로 바꾸기 본문

개발 공부/React

함수형 컴포넌트 class 컴포넌트로 바꾸기

차정 2022. 8. 4. 18:58

함수형 컴포넌트

import { useState } from 'react';
import User from './User';

import classes from './Users.module.css';

const DUMMY_USERS = [
  { id: 'u1', name: 'Max' },
  { id: 'u2', name: 'Manuel' },
  { id: 'u3', name: 'Julie' },
];

const Users = () => {
  const [showUsers, setShowUsers] = useState(true);

  const toggleUsersHandler = () => {
    setShowUsers((curState) => !curState);
  };

  const usersList = (
    <ul>
      {DUMMY_USERS.map((user) => (
        <User key={user.id} name={user.name} />
      ))}
    </ul>
  );

  return (
    <div className={classes.users}>
      <button onClick={toggleUsersHandler}>
        {showUsers ? 'Hide' : 'Show'} Users
      </button>
      {showUsers && usersList}
    </div>
  );
};

export default Users;

클래스 만들기

  class Users { 
   constructor() {
     super()
     this.state = {};
   }
   render () {

   }
  }
  • 생성자 함수는 구문이 인스턴스화 될 때 (리액트가 컴포넌트로 사용되는 클래스를 만날 때)
    자동적으로 호출된다. 생성자에서는 state 초기화와 같은 초기화 작업을 할 수 있다.
  • constrcutor() 사용 시 상위클래스의 생성자를 호출하는 super() 사용해야한다.
  • constructor() 는 초기화 하는 메서드로 초기화가 필요없으면 생략가능하다.

Component

  • Component 임포트 - props를 받으려면 extends Component 필요
  • 확장이란 개념은 모던자바스크립트의 내장 개념
    Component를 extends한 컴포넌트가 props로 접근할 수 있게 됨
import { Component } from 'react'; 
class Users extends Component { 

}

render 메서드

  • render() 메서드는 리액트에 필요한 특정 메서드로 리액트가 jsx코드안에 컴포넌트가 사용된 것을 확인하면 그때 호출하는 메서드로,
    render() 메서드를 통해서 무엇이 화면에 렌더링 되어야하는지 찾는다.
  • render 메서드 안에 함수형 컴포넌트의 return 메서드 넣는다.
    (클래스 컴포넌트의 render() 메서드 안에는 렌더링 할 것을 알려주는 반환값 필요함)
class Users extends Component { 

  constructor() { 
    this.state = { } 
  } 
  render () { 
    return () { 
    } 
  } 
}

state

  class Users extends Component {
   constructor() {
    this.state = {
      showUsers : true,
      more : 'Test'
    }
   }
   toggleUsersHandler() {
    // this.state.showUsers = false; // NOT!
    this.setState((curState) => {
      return { showUsers: !curState.showUsers };
    });
  }
  • 함수형컴포넌트에서는 useState를 여러번 호출할 수 있으나
    클래스 컴포넌트에서는 컴포넌트 구성하는 state를 하나의 객체로 만들어야 한다.
    this.state ={} 이 안에 관리할 state를 다 넣는다.
    사용하던 state 객체는 모두 this.state. 를 붙여준다.

setState

  • state 변경 함수에서 state를 조작할때는 this.state에 접근해서 변경하면 안되고,
    ( this.state.showUsers = false; (X))
  • this.setState라는 특수한 메서드를 사용해야 한다.
    setState는 기존 상태를 덮어쓰지 않고, 기존의 state와 setState가 전달하는 객체를 결합시킨다.
    this.setState({showUser: false} 하면
    기존 state { showUsers : true, more : 'Test' } 와 setState가 전달하는 객체 {showUser: false}가 병합되어
    { showUsers : false, more : 'Test' } 가 된다.
    setState가 바꾸는 state가 이전값에 의존한다면 새로운 상태를 갖는 객체 대신에 함수를 setState를 전달해야 하며,
    객체를 반환한다.

this

  • 클래스 컴포넌트 안에 정의된 함수를 render 안의 return 안에서 사용할 때 함수명 앞에 this.를 붙여서
    이 클래스의 메소드임을 가리켜야한다.(return메서드가 class를 벗어나서???)
  • 자바스크립트에서 함수를 호출하면 호출된 함수 내부의 this가 context를 잃는다.
    this.toggleUsersHandler 함수를 호출했을때 함수의 this는 전역 this를 가리키게 되므로,
    this.setState는 undefined 가 되어버린다.
  • this.toggleUsersHandler.bind(this) 로 render()의 this인 App을 바인딩한다
    => 메서드 내부의 this 예약어가 코드가 평가될 시점의 this와 동일한 내용을 갖도록 설정된다.
  • [참조]
    https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/

클래스형 컴포넌트

import { Component } from 'react';

import User from './User';
import classes from './Users.module.css';

class Users extends Component {
  constructor() {
    super();
    this.state = {
      showUsers: true,
      more: 'Test',
    };
  }

  componentDidUpdate() {
    // try {
    //   someCodeWhichMightFail()
    // } catch (err) {
    //   // handle error
    // }
    if (this.props.users.length === 0) {
      throw new Error('No users provided!');
    }
  }

  toggleUsersHandler() {
    // this.state.showUsers = false; // NOT!
    this.setState((curState) => {
      return { showUsers: !curState.showUsers };
    });
  }

  render() {
    const usersList = (
      <ul>
        {this.props.users.map((user) => (
          <User key={user.id} name={user.name} />
        ))}
      </ul>
    );

    return (
      <div className={classes.users}>
        <button onClick={this.toggleUsersHandler.bind(this)}>
          {this.state.showUsers ? 'Hide' : 'Show'} Users
        </button>
        {this.state.showUsers && usersList}
      </div>
    );
  }
}

export default Users;