본문 바로가기

클라이언트/React
[리액트(React)] Class-based Component

// Class-based Component

- 클래스 기반 컴포넌트

- React 16.8 이전에는 Functional Component가 아닌 Class-based Component를 사용했다.
  (여전히 사용하는 회사들이 많을 수 있으므로.. 공부해야 함..)

* https://sorrel012.tistory.com/360에서 간략하게 언급한 적 있다.

 

[리액트(React)] Component, Props

// 컴포넌트, Component - 사용자 인터페이스를 구성하는 독립적이고 재사용 가능한 부분 - 여러 컴포넌트들을 조립하여 UI를 구성한다. - 컴포넌트명은 항상 대문자로 시작해야 한다. - 컴포넌트 함

sorrel012.tistory.com


// 기본 사용 형태

import { Component } from 'react';

class 컴포넌트명 extends Component {
  render() {
    return ...jsx코드
  }


export default 컴포넌트명;

// props

import { Component } from 'react';

class 컴포넌트명 extends Component {
  render() {
    return <li>{this.props.props명}</li>;
  }
}

export default 컴포넌트명;


- Component를 import해서 사용하기 때문에 this.props.props명으로 props를 받아 사용할 수 있다.


// 함수

import { Component } from 'react';

class 컴포넌트명 extends Component {
  함수명() {
    ...
  }

  render() {
    return ...jsx코드
  }


export default 컴포넌트명;


- Class이기 때문에, JavaScript의 Class에서처럼 함수를 정의하여 사용한다.


// state

import { Component } from 'react';

class 컴포넌트명 extends Component {
  constructor() {
    super();
    this.state = {
      state1명: ... ,
      state1명: ... ,
      
        ...
    };
  }
  
  함수명() {
    this.setState((state) => {
     return {state1명: !state.state1명};
   });
  }

  render() {
    return (
      <>
        {this.state.state1명}
      </>
    );
  }


export default 컴포넌트명;


- 생성자를  활용하여 state를 객체 형태로 정의한다.

- 생성자를 정의할 때는 super()를 호출하여 부모 클래스의 생성자를 먼저 실행한다.

- state를 변경할 때는 this.setState()를 활용해야 한다.
   > 기존의 상태를 override 하지 않고 merge한다.  
   > 원하는 상태만 변경하고, 나머지 상태는 그대로 유지된다.  

- this.setState()를 사용하여 state를 변경할 때도 객체 형태를 유지해야 한다.


// this 바인딩

import { Component } from 'react';

class 컴포넌트명 extends Component {
  constructor() {
    super();
    this.state = {
      state1명: ... ,
      state1명: ... ,
      
        ...
    };
  }
  
  함수명() {
    this.setState((state) => {
     return {state1명: !state.state1명};
   });
  }

  render() {
    return (
      <>
        <button onClick={this.함수명.bind(this)}>
          {this.state.state1명}
        </button>
      </>
    );
  }


export default 컴포넌트명;


※ javaScript의 this는 일반 함수 문법을 사용하면 해당 함수가 호출되었을 때의 컨텍스트를 가리키기 때문에 클래스 컴포넌트를 가리키지 않을 수 있다.

이를 해결하기 위해,

1. 위의 코드처럼 bind 메서드를 사용하여 함수를 명시적으로 바인딩한다.

함수명() {
}

<button onClick={this.함수명.bind(this)}>
     {this.state.state1명}
</button>


- 매번 bind 메서드를 호출해야 하기 때문에 성능 저하가 일어날 수 있다.

2. 화살표 함수를 이용하여 인라인 정의한다.

함수명() {
}

<button onClick={() => this.함수명()}>
     {this.state.state1명}
</button>


3.  함수를 화살표 함수로 정의한다.

함수명 = () => {
}

<button onClick={this.함수명}>
     {this.state.state1명}
 </button>


- 가장 많이 사용되는 방법이다.


4. 생성자에서 함수를 바인딩한다.

constructor() {
  super();
  this.함수명 = this.함수명.bind(this);
}

<button onClick={this.함수명}>
    {this.state.state1명}
</button>

import classes from './User.module.css';
import { Component } from 'react';

class User extends Component {
  render() {
    return <li className={classes.user}>{this.props.name}</li>;
  }
}

export default User;

 

import { Component } 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' },
];

class Users extends Component {
  constructor() {
    super();
    this.state = {
      showUsers: true,
    };
  }
  toggleUsersHandler = () => {
    this.setState((curState) => {
      return { showUsers: !curState.showUsers };
    });
  };

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

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

export default Users;

// LifeCycle

- 클래스 컴포넌트의 생명 주기

- Mounting -> Updating -> Unmounting

- 시간의 흐름에 따라 Component가 생성되고 업데이트 되다가 사라진다.

  • componentDidMount() : 컴포넌트 mount될 때 한 번만 실행된다.
    ≒ useEffect(..., [])
  • componentDidUpdate() : 컴포넌트가 업데이트 될 때 실행된다.
    ≒ useEffect(..., [값])
  • componentWillUnmount() : 컴포넌트가 업데이트 되기 직전 실행된다.
    ≒ useEffect(() => { return () => {...} }, [])

import React from 'react';
import Notification from './Notification';

const reservedNotifications = [
  {
    id: 1,
    message: '오전 미팅',
  },
  {
    id: 2,
    message: '점심식사 시간',
  },
  {
    id: 3,
    message: '퇴근 시간',
  },
];

var timer;

class NotificationList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      notifications: [],
    };
  }

  componentDidMount() {
    const { notifications } = this.state;
    timer = setInterval(() => {
      if (notifications.length < reservedNotifications.length) {
        const index = notifications.length;
        notifications.push(reservedNotifications[index]);
        this.setState({
          notifications: notifications,
        });
      } else {
        this.setState({
          notifications: [],
        });
        clearInterval(timer);
      }
    }, 1000);
  }

  render() {
    return (
      <div>
        {this.state.notifications.map((notification) => (
          <Notification
            key={notification.id}
            id={notification.id}
            message={notification.message}
          />
        ))}
      </div>
    );
  }
}

export default NotificationList;