본문 바로가기
  • soldonii's devlog
Javascript 공부/React

리액트에서 state를 다룰 때 주의해야 할 점

by soldonii 2019. 12. 10.

*Udemy의 "React - The Complete Guide" 강의에서 학습한 내용을 정리한 포스팅입니다.

*자바스크립트와 리액트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. state 객체는 reference type!

DOM에서 P 태그가 있는 부분을 클릭했을 때 해당 데이터가 DOM에서 사라지도록 해보자. App.js 파일에 deletePersonHandler 메소드를 추가한다.

deletePersonHandler = (personIndex) => {
    const persons = this.state.persons;
    persons.splice(personIndex, 1);
    this.setState({persons: persons});
  }

그리고 Person 컴포넌트에 이 메소드를 넘겨주어서 클릭이 일어나면 state를 변경시키므로 DOM에서 사라지게 된다.

{this.state.persons.map((person, index) => {
  return <Person
           click={() => this.deletePersonHandler(index)}
           name={person.name}
           age={person.age} />
})}

위처럼 Person 컴포넌트의 click 프로퍼티의 값으로 콜백함수를 통해 deletePersonHandler 메소드를 넘겨주었다. 그런데 여기서 deletePersonHandler 메소드 안에는 큰 문제가 있다. 그게 무엇일까?

 

자바스크립트에서 객체는 Reference Type이다. 따라서 persons 변수에 현재 담겨있는 값은 this.state.persons가 저장되어 있는 메모리 공간의 주솟값이다. 그런데 이 주솟값에 persons.splice(personIndex, 1)을 할 경우 문제가 발생한다. splice는 원본이 변경되는 mutable한 메소드이다. 따라서 persons.splice는 메모리 주솟값에 저장되어 있는 원본 값에 변형을 가하므로, 이미 this.setState 메소드가 실행되기 이전에 중요한 데이터인 state 데이터에 변형을 가하게 되는 것이다.

 

# 해결책

deletePersonHandler = (personIndex) => {
    const persons = this.state.persons.slice();
  	// const persons = [...this.state.persons]; 이 방법도 가능하다.
    persons.splice(personIndex, 1);
    this.setState({persons: persons});
  }

따라서 위 코드처럼 변수에 this.state의 값을 담아놓을 경우 원본을 그대로 카피한 후 다뤄줘야 한다. 위 코드는 slice를 통해서 this.state.persons의 값을 그대로 복사하고 있다. 주석처리한 부분은 전개 구문(spread operator)를 통해서 값을 복사한 것이다. 둘 중 어떤 방식을 취해도 상관없고 다만 원본이 변형되지 않도록 반드시 값을 복사한 후 사용해야 한다는 점에 주의하자!

댓글