[React] 4. state, props

🏃Dekay (JuniorDeveloper)·2021년 9월 20일
0

React

목록 보기
4/13
post-thumbnail

1. state ✔

  • state컴포넌트 내부에서 바뀔 수 있는 값을 의미한다.
  • props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props읽기 전용으로만 사용할 수 있다.
    즉, props를 바꾸려면 부모 컴포넌트에서 바꿔야 한다.

리액트에는 state도 두 가지 종류가 있다.
1. 클래스형 컴포넌트가 지니고 있는 state
2. 함수형 컴포넌트에서 useState라는 함수를 통해 사용하는 state

1.1 클래스형 컴포넌트의 state

  • src/Counter.js 파일을 생성하여 다음과 같이 코드를 작성했다.
//Counter.js
import React, { Component } from "react";


class Counter extends Component {
    constructor(props) {
        super(props);
        // state의 초깃값 설정
        this.state = {
            number: 0
        };
    }
    render() {
        const { number } = this.state; // state를 조회할 땐 this.state 사용
        return (
            <div>
                <h1>{number}</h1>
                <button
                // onclick을 통해 버튼이 클릭되면 호출할 함수
                onClick={() => {
                    // this.setState를 사용하여 state에 새로운 값 삽입 가능
                    this.setState({ number: number + 1 })
                }}
                >
                    +1
                </button>
            </div>
        );
    }
}

export default Counter;
  • 위의 코드 처럼 컴포넌트에 state를 설정할 때는 constructor 메소드를 사용한다.
  • 또한, 클래스형 컴포넌트에서 constructor를 사용할 때는 반드시 super(props)를 호출해야 한다.
  • 왜냐하면, 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출하기 때문이다.
  • 새로 생성한 Counter 컴포넌트를 App에서 불러와 렌더링하기 위해 아래와 같이 작성했다.
//App.js
import React from 'react';
import Counter from './Counter';

const App = () => {
  return <Counter />
}

export default App;
  • 위와 같은 코드로 Counter 컴포넌트를 렌더링 하면 +1 버튼을 클릭하면 숫자가 1씩 증가하는 브라우저를 확인할 수 있다.

1.1.1 state를 constructor에서 꺼내기

  • 앞에서 state의 초깃값을 지정하기 위해 constructor 메서드를 선언하였는데, 다음과 같이 사용하여 초깃값을 설정할 수 있다.
class Counter extends Component {
    state = {
        number: 0
    };
    render () {
      const { number } = this.state;
      return (...);
    }
}
  • 처음에 state에 초깃값을 설정해서 사용하는 방법이 개인적으로 더 괜찮아 보인다.

1.1.2 this.setState에 객체 대신 함수 인자 전달

  • this.setState를 사용하여 state값을 업데이트할 때는 비동기적으로 업데이트된다.
  • 만약, onclick에 설정한 함수 내부에서 this.setState를 두 번 호출하면 두 번 클릭한 것 이지만, this.setState를 사용한다고 해서 state 값이 바로 바뀌지 않기 때문에 결과는 같다.
onclick{() => {
  // this.setState를 사용하여 state에 새로운 값 지정
  this.setState({ number: number + 1 });
  this.setState({ number: this.state.number + 1 });
}}
  • 이를 해결하기 위한 방법으로 this.setState를 사용할 때 객체 대신 함수를 인자로 넣어주면 된다.
this.setState((prevState, props) => {
  return {
    // 업데이트하고 싶은 내용
  }
})
  • 여기서 prevState기존 상태이고, props현재 지니고 있는 props를 의미한다.
    * 업데이트 과정에서 props가 필요하지 않으면 생략 가능.
//Counter.js
onClick={() => {
  this.setState(prevState => {
    return {
      number: prevState.number + 1
    };
  });
  // 위 코드와 아래 코드는 완전히 같은 기능을 한다.
  // 아래 코드는 함수에서 바로 객체를 반환하는 기능
  this.setState(prevState => ({
    number: prevState.number +1
  }));
}}

1.2 함수형 컴포넌트에서 useState 사용

  • 앞서 언급했던 내용과 같이 리액트 16.8 이전 버전에서는 함수형 컴포넌트에서 state를 사용할 수 없었지만, 업데이트 이후 useState 함수를 사용하여 state를 사용할 수 있다.
  • 사용하기 위해서 Hooks라는 것을 사용하게 된다.

1.2.1 useState 사용하기

  • useState를 사용하기 위해서 새로운 컴포넌트 src/Say.js 파일을 생성하여 다음과 같이 코드를 작성했다.
//Say.js
import React, {useState} from "react";

const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕!');
    const onClickLeave = () => setMessage('잘가!');

    return (
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1> {message} </h1>
        </div>
    );
};

export default Say;
  • useState 함수의 인자에는 상태의 초깃값을 넣어준다.
    * 클래스형 컴포넌트에서는 state의 초깃값은 객체 형태를 넣어야 한다고 했는데, useState는 객체가 아니어도 상관없다.
  • 위와 같이 상태를 바꿔주는 함수를 세터(Setter) 함수라고 한다.
  • 아래와 같이 App.js를 수정하여 Say.js 컴포넌트를 확인했다.
//App.js
const App = () => {
  return <Say />;
};

1.2.2 한 컴포넌트에서 useState 여러 번 사용하기

  • useState는 한 컴포넌트에서 여러번 사용해도 상관없으며, 다음과 같은 코드로 관리가 가능하다.
//Say.js
const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕!');
    const onClickLeave = () => setMessage('잘가!');

    const [color, setColor] = useState('black');

    return (
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1 style={{ color }}>{message}</h1>
            <button style={{ color: 'red' }} onClick={() => setColor('red')}>빨간색</button>
            <button style={{ color: 'green' }} onClick={() => setColor('green')}>초록색</button>
            <button style={{ color: 'blue' }} onClick={() => setColor('blue')}>파란색</button>
        </div>
    );
};
  • 위의 코드를 사용하면 출력된 텍스트의 색상을 변경할 수 있다.

2. props ✔

  • propsproperties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다.
  • props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에 설정할 수 있다.
  • 쉽게 말해서 컴포넌트의 속성값으로 부모 컴포넌트로부터 전달 받은 데이터를 지니고 있는 객체라고 생각하자.

2.1 JSX 내부에서 props 렌더링

  • props 값은 컴포넌트 함수의 파라미터로 받아와서 사용할 수 있다.
  • props를 렌더링할 때 JSX 내부에서 { } 기호로 감싸주어야 한다.
const MyComponent = props => {
    return <div>제 이름은 {props.name} 입니다.</div>;
};

2.2 props 값 지정하기

  • 1.4.1절과 같이 MyComponent.js를 수정 했다면 App.js 코드는 아래와 같이 수정하면 정상적으로 작동한다.
const App = () => {
  return <MyComponent name="박대경" />;
}

// 👉 결과: 제 이름은 박대경 입니다.

2.3 props 기본값 설정

  • 만약 name 값을 지정하지 않게 되었을 경우에는 제 이름은 입니다.가 출력된다.
  • 아래의 코드 처럼 작성하면 props의 기본값을 설정할 수 있다.
const MyComponent = props => {
    return <div>제 이름은 {props.name} 입니다.</div>;
};

MyComponent.defaultProps = {
    name: '박대경'
} // 기본값 설정

2.4 태그 사이의 내용을 보여주는 children

  • children리액트 컴포넌트를 사용 할 때 컴포넌트 태그 사이의 내용을 보여주는 props이다.
// App.js
const App = () => {
  return <MyComponent>박대경</MyComponent>;
}

//MyComponent.js
const MyComponent = props => {
    return (
        <div>
            제 이름은 {props.name} 입니다. <br />
            children 값은 {props.children}
            입니다.
        </div>
    );
};

MyComponent.defaultProps = {
    name: '박대경'
}
// 👉 결과
제 이름은 박대경 입니다.
childern 값은 박대경 입니다.

2.5 props 내부 값 추출하기

  • 지금까지 MyComponent에서 props 값을 조회할 때마다 props.name, props.children과 같이 props. 키워드를 앞에 사용했는데, ES6의 비구조화 할당 문법을 사용하면 내부 값을 바로 추출할 수 있다.
//MyComponent.js
const MyComponent = props => {
    const { name, children } = props;
    return (
        <div>
            제 이름은 {name} 입니다. <br />
            children 값은 {children}
            입니다.
        </div>
    );
};

MyComponent.defaultProps = {
    name: '박대경'
}
  • 위의 코드를 사용하면 name 값과 children 값을 더 짧은 코드로 사용할 수 있는데, 함수의 파라미터 부분에도 사용할 수 있다.
    * props => ({name, children})

2.6 propTypes를 통한 props 검증

  • 컴포넌트의 필수 props를 지정하거나 props의 타입(type)을 지정할 때 propTypes를 사용한다.
  • 사용 방법은 defaultProp을 설정하는 것과 비슷한데 코드 상단에 import 구문을 사용하여 propTypes를 불러와야 한다.
//MyComponent.js
import propTypes from 'prop-types';

MyComponent.propTypes = {
    name: propTypes.string
};
  • 위의 코드를 MyComponent파일에 추가한 뒤 name 값을 3으로 전달하게 되면 브라우저 개발자 도구의 Console 탭에 Warning을 출력한다.

2.7 isRequired를 사용하여 propTypes 설정

  • 2.6절과 같이 propTypes를 지정하지 않았을 때 경고 메세지를 띄워주어야 한다.
  • 사용 방법은 propTypes를 지정할 때 뒤에 isRequired를 붙여 사용하면 된다.
//MyComponent.js

MyComponent.propTypes = {
    name: propTypes.string.isRequired
};
  • string 외에도 propTypes의 종류는 많이 있다.
    예를 들어, array, arrayOf, bool, func, number, object, sybol 등등.
  • 더 자세한 정보는 prop-types에서 확인할 수 있다.

2.8 클래스형 컴포넌트에서 props 사용

  • 클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 된다.
  • 또한, defaultProps, propTypes는 같은 방식으로 사용할 수 있다.
//MyComponent.js
class MyComponent extends Component {
    render () {
        const { name, children } = this.props; // 비구조화 할당
        return (
            <div>
                제 이름은 {name} 입니다.
                children 값은 {children}
                입니다.
            </div>
        );
    }
}

MyComponent.defaultProps = {
    name: '박대경'
}

MyComponent.propTypes = {
    name: propTypes.string.isRequired
};
  • 또한, 클래스형 컴포넌트에서 defaultPropspropTypes를 설정할 때 class 내부에 지정할 수 있는데 static을 사용하면 된다.
static defaultProps = {
  name: '박대경'
};

ststic propTypes = {
  name: propTypes.string
};

render() {
  ...
}

props와 state 생각 정리 ✍

  • propsstate는 둘 다 컴포넌트에서 사용하거나 렌더링할 데이터를 지니고? 있지만 역할이 다르다 라고 생각하자.

  • props부모 컴포넌트가 설정하고, state는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트 가능하다.

  • 그리고 앞으로 useState를 사용하여 컴포넌트를 만드는 것을 습관화해야 코드가 더 깨끗? 간결해질 것 같다.

  • 그리고 defaultPropspropTypes는 꼭 사용해야 하는 것은 아니지만, 나중에 프로젝트를 진행할 때 컴포넌트에 어떤 props가 필요한지 알아야 할테니 복습 해야겠다.

  • 함수형 컴포넌트클래스형 컴포넌트의 성능 차이는 업데이트로 인해 거의 없다 메모..✔

end

profile
Believe you can & you're half way there 🙏

0개의 댓글