본문 바로가기
ERROR

eslint 오류: State initialization should be in a constructor eslint(react/state-in-constructor)

by 로맨틱스터디 2023. 1. 31.
728x90
반응형

발단

조금 예전 리액트 강의들을 따라하다보면 함수형 컴포넌트보다는 클래스형 컴포넌트를 사용한 것들이 많고,

클래스형 컴포넌트에서 state의 초깃값 정의 부분도 constructor() 생성자 함수 없이 그냥 곧바로 정의해주는 경우가 많았다.

 

class Header extends Component {
  state = {
    buttonDisplay: "none"
  };

 

에러 메시지

이는 eslint 오류를 발생시키는데,
바로, class 컴포넌트의 state의 초깃값 설정 부분은 constructor() 생성자 함수 안에 들어가야한다는 것이다
State initialization should be in a constructor eslint(react/state-in-constructor)

 

해결

state 초깃값 정의 부분을 constructor() 생성자 함수 안에 넣어주면 간단하게 해결 가능하다.

 

class Header extends Component {
  constructor(props) {
    super(props);
    this.state = {
        buttonDisplay: "none",
    };
}
단, constructor() 생성자 함수를 정의할 때 주의할 점은
  (1) 파라미터로 props를 받아주어야 하고
  (2) super(props);를 호출해주어야 하며
  (3) state 앞에 this를 붙여주어야 한다

 

 

 


Tip. class 컴포넌트 관련 개념

 

더보기

class

: 객체를 생성하기 위해 ES6에서 추가된 문법 (리액트 문법 X)

 

class 선언 방법

class Header extends Component {
  ...
}
(1) class 뒤에 클래스명을 입력 해주고
(2) 객체를 의미하는 {} 안에 값을 넣습니다.
(3) extends: 다른 클래스의 자식 클래스를 생성하기 위해 사용

 

constructor() 생성자 함수

:  class 객체를 만드는 데 필요한 값에 대해서 선언해 주고 초기화해주는 특수 메서드. 

constructor(props) {
    super(props);
    this.state = {
      buttonDisplay: "none",
    }
}
(1) 클래스 안에 한 개만 존재할 수 있다
(2) super() : 부모 클래스(React.Component)의 constructor() 호출 가능, 항상 생성자의 첫줄에 와야 한다 

 

this

: 클래스 컴포넌트에 선언한 놈들을 참조하기 위해 사용

  1. state (+setState)
  2. props
  3. refs
  4. 컴포넌트 메서드 ⇒ 이벤트 핸들링시 예외 발생
  5. 생명주기 매서드
class BoardDetail extends Component {
    constructor(props) {
        this.state = { board: [], }  // 클래스 컴포넌트 BoardDetail의 state
    }
    componentDidMount() {
        if (this.props.location.query !== undefined) { this.getDetail(); } 
        // 클래스 컴포넌트 BoardDetail의 props
        // 클래스 컴포넌트 BoardDetail의 getDetail() 커스텀메서드 호출
        else { window.location.href = "/"; }
    }
    deleteBoard = (_id) => {
            ...
    }

    render() {
        return (
            <Button onClick={this.deleteBoard.bind(nulll, this.props.location.query._id)}>
    )
}

this.state = BoardDetail.state / this.props = BoardDetail.props / this.getDeatil() = BoardDetail.getDetail()

이런 식으로 인스턴스에 .을 붙여 호출시 -> 정상적으로 클래스 컴포넌트에 바인딩되어 참조 가능 

 

But, 컴포넌트에서 선언한 메서드를 -> JSX 이벤트 핸들러의 콜백 함수로 를 전달할 때 문제 발생

= 메서드를 다른 변수에 옮겨 호출시 -> TypeError 발생 

deleteBoard = (_id) => {
// axios의 메서드들(post(), then(), catch())을 -> deleteBoard 변수로 옮긴 후
   axios 
      .post() 
      .then()
      .catch()
}

<Button onClick={this.deleteBoard}> // deleteBoard() 변수로 호출
// 원래 바인딩되어 있던 클래스 BoardDetail을 잃어버리고 -> 전역 객체인 window/global에 바인딩되어 참조 불가능해짐

 

해결 방법

[1] bind()

: 어떤 함수의 this를 명시하는 역할을 하는 Function 객체의 메서드

<Button onClick={ this.deleteBoard.bind(nulll, this.props.location.query._id)}>

bind() 호출시 -> 인자로 받은 객체를 this로 하는 새로운 함수를 리턴

- 이벤트 핸들러로 bind()를 호출한 메서드 this.deleteBoard.bind()를 넘긴다

- constructor()에 작성한다

 

[2] 화살표 함수

: 화살표 함수는 다른 함수와 달리 따로 this를 가지고 있지 않고, 항상 상위 스코프의 this에 바인딩한다(lexical this)

 render() {
        return (
            <Button onClick={ () => this.deleteBoard() } >
        )
}

상위 스코프인 render() 메서드의 this인 클래스 컴포넌트 BoardDetail에 바인딩


참조

https://maxkim-j.github.io/posts/react-component-this/

 

 

728x90
반응형