TIL 035 | React의 state와 props

JU CHEOLJIN·2021년 8월 26일
0

React

목록 보기
4/15
post-thumbnail

📲 state & props

리액트를 처음 접하면 당황스러운 일이, 바로 stateprops 이다. 리액트는 선언적 특징을 가지고 있기 때문에 직접 DOM 요소를 조작하지 않고 state 의 변화를 통해서 UI 를 리-렌더링한다. 그렇기 때문에 이전에 명령을 통해서 조작하던 방식과는 사고의 흐름이 다르다고 느껴졌다. 하지만, stateprops 은 알면 알수록 재밌고 흥미로운 요소이다. 이에 대해서 정리해보려고 한다.

state

state 는 컴포넌트가 가지고 있는 상태값을 의미한다. 더 정확히는 UI에 대한 정보를 담고 있는 객체라고 볼 수 있다. state 는 불변값이 아니며 언제든지 사용하고 변경될 수 있다.

class Main extends Component {
  state = {
    feeds: [],
  };

  render() {
    return (
      <main className="main>
        <Nav />
            <section className="main__feeds">
              {this.state.feeds.map(feed => (
                <Feed key={feed.id} feed={feed} comments={feed.comments} />
              ))}
            </section>
            <Aside />
        </main>
    );
  }
}

export default Main;

위의 예시는 메인 페이지의 컴포넌트에서 state 를 가지고 있는 모습이다. 메인 페이지는 statefeeds 라는 배열을 가지고 있다. 이 배열 안에는 또 각 피드의 정보를 담고 있는 객체들이 들어갈 예정이다. 지금은 생성하면서 초기화만 진행했기 때문에 feeds 에 빈 배열이 들어와 있다.

// mock data 받아오기
componentDidMount = () => {
    fetch('http://localhost:3000/data/CommentDataCJ.json', {
      method: 'GET',
    })
      .then(result => result.json())
      .then(feeds => {
        this.setState({
          feeds,
        });
      });
  };

위의 코드는 componentDidMount() 를 통해서 mock data 를 받아오고 이를 이용해서 setState 를 진행했다. 여기서 setState 를 사용해서 업데이트를 한 점을 보자. stateUI에 대한 정보를 가지고 있고 이를 렌더링 하기 위해서 존재한다고 볼 수 있다. 만약, state 의 값을 직접 조작하는 경우에는 state의 변화는 있겠지만 render() 가 호출되지 않아서 리-렌더링이 생겨나지 않는다. 그렇기 때문에 setState() 를 호출하고 이 때, render() 가 호출되기 때문에 정상적으로 UI를 그릴 수 있게 된다.

setState의 비동기성

state 를 사용하면서 겪었던 어려움은 setState() 가 비동기적으로 작동하는 점이었다. state 가 잘 업데이트 되는지 확인하기 위해서 console.log(this.state) 를 사용하는 과정에서 한 박자 느린 반응을 보게 된다거나 전혀 예상하지 못한 흐름으로 동작한다거나 하는 오류들을 겪었다. 특히, IDPASSWORD 를 입력하는 상황에서 한 쪽이 사라지는 경우를 겪기도 했다.

this.setState({
  counter: this.state.counter + this.props.increment,
});

만약 위와 같은 코드를 사용하게 된다면 카운터가 제대로 업데이트 되지 않는 상황을 겪을 수도 있다. 되도록 this.statethis.props 을 사용할 때 비동기적으로 업데이트 될 수 있음을 명심하고 사용하는 것이 좋다.

props

state 가 컴포넌트 본인이 가지고 있는 상태값이라면 props 은 부모로부터 받은 속성 객체라고 볼 수 있다. 여기에는 배열, 객체 등이 들어갈 수 있고 메소드도 가능하다. state 는 본인이 가지고 있는 값이기 때문에 얼마든지 변경이 가능하지만 props 는 읽기 전용이기 때문에 자식 컴포넌트에서 수정할 수가 없다.

사용하기

class Comment extends Component {
  handleDelete = e => {
    this.props.onDelete(this.props.reply);
  };

  handleLike = e => {
    this.props.onLike(this.props.reply);
  };

  render() {
    const { userName, comment, isUser, isLike } = this.props.reply;
    return (
      <li className="comment-cheoljin">
        <span>{userName}</span>
        <span>{comment}</span>
        <button
          type="button"
          className="comment__heart"
          onClick={this.handleLike}
        >
          <i className={isLike ? 'fas fa-heart' : 'far fa-heart'} />
        </button>
        <button
          type="button"
          className="comment__delete"
          onClick={this.handleDelete}
        >
          <i
            className={isUser ? 'far fa-trash-alt' : 'far fa-trash-alt none'}
          />
        </button>
      </li>
    );
  }
}

export default Comment;

위의 예시를 보자. props 를 구조분해할당을 통해서 userName, comment, isUser, isLike 로 나눴다. 그 후에 각 필요한 부분에 {} 을 통해 사용했다. 또한, handleDelete 등의 함수를 보면 부모 컴포넌트로부터 전달 받은 props 객체의 메소드인 onDelete를 호출하는 함수 임을 알 수 있다.

이처럼 props 는 부모 컴포넌트와 자식 컴포넌트를 연결해주는 다리의 역할을 한다.

더 설명해보자면 자식 컴포넌트인 Comment 에 있는 <button> 에서 onClick 이벤트가 발생하게 되면 handleDelete 함수가 호출되고 handleDelete 함수는 props로 전달받은 onDelete 함수를 호출한다. 이때 인자로 propsreply 를 전달할 수 있다.

위와 같은 방식으로 자식 요소에서 발생한 이벤트를 부모 컴포넌트로 전달해서 state 를 업데이트 할 수 있다.

✨ 마치며

오늘은 stateprops 에 대해서 간단하게 정리했다. 리액트를 처음 접하게 되는 경우에는 어떻게 이용해야 좋을지 막막한 기분을 느끼는 경우가 많은데 사용하는 방법에 대해서 잘 이해한다면 바닐라 자바스크립트만을 사용하는 경우보다 훨씬 편함을 알 수 있다.

앞으로 평생 함께해야 할 stateprops. 막히는 부분이 있는 경우에는 꼭 리액트 공식 문서에서 답을 찾으며 계속 공부해 볼 예정이다.

profile
사회에 도움이 되는 것은 꿈, 바로 옆의 도움이 되는 것은 평생 목표인 개발자.

0개의 댓글