리액트 - props와 state

velopert님의 블로그에서 리액트 기초 과정을 보고 리액트를 알아가는 시간을 가졌으며,
해당 포스팅은 위 과정을 이해한대로 정리한 것이다.
(https://velopert.com/reactjs-tutorials)

리액트 컴포넌트에서 다루는 데이터는 propsstate 두 개로 나뉜다.

props : 부모 컴포넌트가 자식 컴포넌트에게 주는 값 (받아온 값은 직접 수정 불가능 ❌)
state : 컴포넌트 내부에서 선언한 값 (값 변경 가능 ⭕️)

새 컴포넌트 만들기

MyName이라는 이름의 컴포넌트를 만들자.

import React, { Component } from 'react';

class MyName extends Component{
    render(){
        return(
            <div>
                안녕하세요. 제 이름은 <b>{this.props.name}</b>입니다.
            </div>
        );
    }
}

export default MyName;

이때 this. 키워드를 통해 자신이 받아온 props값을 조회할 수 있으며, name이라는 props를 보여준다.

App.js를 아래와 같이 수정하고 실행하자.

import MyName from './MyName';

function App() {
  return (
    <MyName name="리액트"/>
  );
}

제대로 잘 받아오는 것을 볼 수 있다.

defaultProps

props의 기본값을 설정할 수 있다.

static defaultProps = {
	name: '기본이름'
}

or

 MyName.defaultProps = {
	name: '기본이름'
}

함수형 컴포넌트

함수형태로 컴포넌트를 작성한다.

const MyName = ({ name }) => {
	return(
    	<div>
        	저의 이름은 {name} 입니다.
        </div>
    );
};

stateLifeCycle이 빠져있다는 것이 클래스형 컴포넌트와의 차이점이다.
초기 마운트가 미세하게 빠르고, 메모리 자원을 덜 사용하는 장점이 있으나, 컴포넌트를 무수히 많이 렌더링 하는 경우가 아니라면 큰 차이는 없다.

state

동적인 데이터를 다룰 때 사용한다.

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

    handelIncrease = () => {
        this.setState({
            number: this.state.number + 1
        });
    }
    
    handelDecrease = () => {
        this.setState({
            number: this.state.number - 1
        });
    }

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

컴포넌트의 state를 정의할 때는 class fields 문법을 사용해서 정의한다.
class fields를 사용하지 않는다면, 아래와 같이 사용한다.

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

constructor를 작성하면, 기존의 클래스 생성자를 덮어쓰게 된다.
리액트 컴포넌트가 지니고 있던 실행자를 super를 통해 미리 실행하고,
그 다음 우리의 작업인 state를 설정할 수 있도록 작성하였다.
class fields와 constructor를 모두 사용한다면, 실행 순서는 class fields -> constructor이다.

메소드 작성

   handelIncrease = () => {
        this.setState({
            number: this.state.number + 1
        });
    }
    
    handelDecrease = () => {
        this.setState({
            number: this.state.number - 1
        });
    }

만약 아래와 같은 방식으로 메소드를 작성하면, 함수에 버튼 클릭이벤트가 전달 되는 과정에서 this와의 연결이 끊기게 된다.

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

즉, this가 undefined로 나타나는 것이다.
이를 해결하려면 constructor를 아래와 같이 수정한다.

constrictor(props){
    super(props);
    this.handleIncrease = this.handleIncrease.bind(this);
    this.handleDecrease = this.handleDecrease.bind(this);
}

setState

state의 값을 바꾸기 위해서는 this.setState를 무조건 거쳐야한다.
setState는 객체로 전달되는 값만 업데이트를 해준다.

state = {
	number:0,
	foo: 'bar'
}

위와 같은 코드를 작성하고, this.setState({number:1});를 하면 foo는 그대로 남고, number값만 업데이트 되는 것이다.
setState는 또한 객체의 깊숙한 곳까지 확인하지 못하므로
아래와 같은 코드는 기존 foo 객체만 바뀔뿐이다.

state = {
	number:0,
	foo: {
    	   foobar: 2
    }
}

위와 같은 상황에서는 아래와 같이 코드를 수정해야 한다.

state = {
	number:0,
	foo: {
    	   ...this.state.foo,
    	   foobar: 2
    }
}

...은 자바스크립트의 전개연산자이다. 기존의 객체안 내용을 해당 위치에 풀어준다는 뜻이다.
그 다음, 설정하고 싶은 값을 또 넣어주면 해당 값을 덮어쓰게 된다.

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

기존 코드는 this.state를 중복 조회하므로 아래와 같이 변경할 수 있다.

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

비구조화 할당이라는 문법을 사용하면 더 나아가 아래와 같은 코드로 변경이 가능하다.

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

이 중 마음에 드는 코드를 골라 사용하면 된다.

   handelIncrease = () => {
   	const {number} = this.state;
        this.setState({
            number: number + 1
        });
    }
    
    handelDecrease = () => {
        this.setState({
           ({number}) = > ({
    		number: number - 1
    	   })
        });
    }

이벤트 설정

리액트와 html의 이벤트 함수 설정시 차이점 (주의 ❗️)
html

<button onclick="alert('hello');">Click Me</button>
<button onclick={this.handleIncrease}>+</button>
  • 이벤트 이름은 camelCase 형식으로 설정 ex) onClick, onMouseDown
  • 이벤트에 전달하는 값은 함수! onClick={this.handleIncrease()}와 같은 방식은 렌더링 → 함수호출 → setState → 렌더링의 무한 반복이 된다.

이제 오늘 배운 내용을 아래와 같이 적용하고 실행해보자.

import Counter from './Counter';

function App() {
  return (
    <Counter/>
  );
}

export default App;

좋은 웹페이지 즐겨찾기