본문 바로가기
프로그래밍 개발/ReactJs

ReactJs - props 와 state

by Jinseok Kim 2021. 1. 5.
반응형

 

props 와 state

 

 

  • 리액트 컴포넌트에서 다루는 데이터는 props, state 이 두개로 나뉜다.
  • props 는 부모 컴포넌트가 자식 컴포넌트에게 주는 값이다. 자식 컴포넌트에서는 props 를 받아오기만하고, 받아온 props 를 직접 수정 할 수 는 없다.
  • 반면에 state 는 컴포넌트 내부에서 선언하며 내부에서 값을 변경 할 수 있다.

 

 

 

 

props

 

 

 

 

아래와 같이 새 컴포넌트를 만든다.

 

Name.js

import React, { Component } from 'react';

class Name extends Component {
  render() {
    return (
      <div>
        Hi My name is <b>{this.props.name}</b> 입니다.
      </div>
    );
  }
}

export default Name;

 

  • 자신이 받아온 props 값은 this. 키워드를 통하여 조회 할 수 있다.

 

 

 

 

 

 

App.js에서 name 이라는 props 를 보여주도록 설정해줄 수 있다.

 

App.js

import React, { Component } from 'react';
import MyName from './Name';

class App extends Component {
  render() {
    return (
      <MyName name="김진석" />
    );
  }
}

export default App;

 

  • import 를 통하여 컴포넌트를 불러오고, 렌더링한다.
  • 이렇게 컴포넌트를 만들고나면, 일반 태그를 작성하듯이, 작성해주면 된다. 그리고 props 값은 name="김진석" 이런식으로 태그의 속성을 설정해주는 것 처럼 해준다.

 

 

 

 

 

defaultProps

 

 

  • 가끔씩은 실수로 props 를 빠트려먹을 때가 있다.
  • 혹은, 특정 상황에 props 를 일부러 비워야 할 때도 있는데 그러한 경우에, props 의 기본값을 설정해줄 수 있는 defaultProps가 있다.

 

import React, { Component } from 'react';

class Name extends Component {
  static defaultProps = {
    name: '기본이름'
  }
  render() {
    return (
      <div>
        Hi my name is <b>{this.props.name}</b> 입니다.
      </div>
    );
  }
}

export default Name;

 

  • 위의 처럼 App.js에서 <Name /> 이런식으로 name 값을 생략해버리면 "기본이름" 이 나타나게 될 것이다. 

 

 

 

 

함수형 컴포넌트

 

 

  • 단순히 props 만 받아와서 보여주기만 하는 컴포넌트의 경우엔 더 간편한 문법으로 작성할 수 있는 방법이 있다. 바로, 함수형태로 작성하는 것이다.

 

import React from 'react';

const Name = ({ name }) => {
  return (
    <div>
      hi My Name is {name} 입니다.
    </div>
  );
};

export default Name;

 

  • 함수형 컴포넌트와 클래스형 컴포넌트의 주요 차이점은, state 와 LifeCycle 이 빠져있다는 점이다.
  • 그래서, 컴포넌트 초기 마운트가 아주 미세하게 빠르고, 메모리 자원을 덜 사용한다.
  • 미세한 차이이니, 컴포넌트를 무수히 많이 렌더링 하게 되는게 아니라면 성능적으로 큰 차이는 없다.

 

 

 

 

 

state

 

 

  • 컴포넌트 내부에서 선언하며 내부에서 값을 변경 할 수 있다.
  • 이때 두 가지 형식으로 state을 이용할 수 있다.

 

 

 

 

 class fields형식을 쓰지 않은 state

 

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    }
    this.handleIncrease = this.handleIncrease.bind(this);
    this.handleDecrease = this.handleDecrease.bind(this);
  }

   handleIncrease() {
    this.setState({
      number: this.state.number + 1
    });
  }

  handleDecrease() {
    this.setState({
      number: this.state.number - 1
    });
  }


}

 

  • constructor 에서 super(props) 를 호출 한 이유는, 우리가 컴포넌트를 만들게 되면서, Component 를 상속했으며, 우리가 이렇게 constructor 를 작성하게 되면 기존의 클래스 생성자를 덮어쓰게 된다.
  • 그렇기에, 리액트 컴포넌트가 지니고있던 생성자를 super 를 통하여 미리 실행하고, 그 다음에 할 작업 (state 설정) 을 해주는 것이다.
  • 또 함수가 버튼의 클릭이벤트로 전달이 되는 과정에서 "this" 와의 연결이 끊겨버리기 때문에 따로 constructor에서 바인딩을 해주어야한다.

 

 

 

 

class fields형식을 쓴 state

 

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0
  }

  handleIncrease = () => {
    this.setState({
      number: this.state.number + 1
    });
  }

  handleDecrease = () => {
    this.setState({
      number: this.state.number - 1
    });
  }

  render() {
    return (
      <div>
        <h1>카운터</h1>
        <div>값: {this.state.number}</div>
        <button onClick={this.handleIncrease}>+</button>
        <button onClick={this.handleDecrease}>-</button>
      </div>
    );
  }
}

export default Counter;

 

  • class fields 를 사용하는건 편의를 위함이다. 확실히 constructor 에 넣는것보다는 효율적이다.
  • 에로우 함수를 적용하면 this을 바인딩 하지 않아도 되기 때문에 따로 바인딩 할 필요도 없어졌기 때문이다.

 

 

 

 

setState

 

  • state 에 있는 값을 바꾸기 위해서는, this.setState 를 무조건 거쳐야한다.
  • 리액트에서는, 이 함수가 호출되면 컴포넌트가 리렌더링 되도록 설계되어있다.

 

 

this.setState({
  number: 0,
  foo: {
    ...this.state.foo,
    foobar: 2
  }
});

 

  • 기존의 객체안에 있는 내용을 해당 위치에다가 풀어준다는 의미이다.
  • 그 다음에 설정하고 싶은 값을 또 넣어주면 해당 값을 덮어쓰게 된다

 

 

 

setState에 객체 대신 함수를 전달하기

 

 

  • setState 를 사용하여 값을 업데이트하게 될 때, 기존의 값을 참고하여 값을 업데이트를 하게 될 때, 조금 더 나은 문법으로 할 수 있다.

 

 

this.setState({
  number: this.state.number + 1
});

위의 코드는 굳이 또 this.state 를 조회해야 한다.

this.setState(
  (state) => ({
    number: state.number
  })
);

setState 에 updater 함수를 만들어서 전달해 주었다.

this.setState(
  ({ number }) => ({
    number: number + 1
  })
);

 (state) 가 ({ number }) 가 됐다. 이건 비구조화 할당 이라는 ES6+의 최신 문법이다.

const { number } = this.state;
this.setState({
  number: number + 1
})

코드를 조금 덜 작성하고 싶다면 이렇게도 할 수 있다.

 

 

 

 

 

이벤트 설정

 

 

render 함수에서 이벤트 설정을 할 수있다.

 

 

 

 render() {
    return (
      <div>
        <h1>카운터</h1>
        <div>값: {this.state.number}</div>
        <button onClick={this.handleIncrease}>+</button>
        <button onClick={this.handleDecrease}>-</button>
      </div>
    );
  }

 

  • 버튼이 클릭되면 우리가 준비한 함수가 각각 호출되도록 설정해주었다.html 에서는 onclick 속성에 클릭되면 실행 할 자바스크립트를 문자열 형태로 넣어준다.
  • 하지만 리액트에서 이벤트 함수를 설정할때 html 과 다음과 같은 사항이 다르다. 이벤트이름을 설정 할 때 camelCase 로 설정해주어야 한다.
  • onclick 은 onClick, onmousedown 은 onMouseDown, onchange 는 onChange 이런식으로 말이다.
  • 이벤트에 전달해주는 값은 함수 여야 한다. 만약에 onClick={this.handleIncrease()} 이런식으로 하게 된다면, 렌더링을 할 때 마다 해당 함수가 호출이됩니다. 렌더링 -> 함수 호출 -> setState -> 렌더링 -> 함수 호출 -> 무한반복.. 이렇게 되버린다.
  • 즉 렌더링 함수에서 이벤트를 설정 할 때 만든 메소드를 호출하면 안된다.

 

 

 

 

 

 

 

반응형

'프로그래밍 개발 > ReactJs' 카테고리의 다른 글

ReactJs - input  (0) 2021.01.06
ReactJs - LifeCycle API  (0) 2021.01.06
ReactJs - JSX 기본  (0) 2021.01.05
ReactJs - Update , Delete기능 구현하기  (0) 2021.01.04
ReactJs - Create 기능 구현  (0) 2021.01.04

댓글