3. 리액트 컴포넌트

맨날·2021년 5월 9일
0

리액트 컴포넌트란

UI를 재사용 가능한 여러 조각으로 나누어 놓은 것이 컴포넌트입니다.

함수형 컴포넌트와 클래스형 컴포넌트

리액트에서는 컴포넌트를 정의하는 방법으로 2가지를 제공하고 있습니다. 함수형 컴포넌트와 클래스형 컴포넌트입니다.

// 함수형 컴포넌트
function Welcome() {
  return <div>Hello World</div>
}
// 클래스형 컴포넌트
class Welcome extends React.Component {
  render() {
    return <div>Hello World</div>
  }
}

Props

Props는 부모 컴포넌트가 자식 컴포넌트에게 값을 할당하는 방법입니다. 이때, 자식 컴포넌트에서는 Props를 수정하여서는 안됩니다.

자식의 JSX에<Child name="hi" /> 처럼 props를 넘겨줄 수 있습니다. 자식 컴포넌트에서는 props 파라미터를 통해서 값을 조회할 수 있습니다. 그리고 태그 사이에 내용을 작성하면 위처럼 props.children 으로 값을 조회할 수 있습니다.

function Parent() {
  return <Child name="hi">Hello World</Child>
}

function Child(props) {
  return <div>{props.children + props.name}</div>
}

비구조할당 문법을 사용하면 좀더 간결하게 props의 값을 가져 올 수 있습니다.

function Parent() {
  return <Child name="hi" id="hello">Hello World</Child>
}

function Child({ name, id, children }) {
  return <div>{children + name + id}</div>
}

Props의 기본값과 타입 설정

컴포넌트에 defaultProps를 설정하면 기본값을 설정할 수 있습니다. 부모가 props를 설정하지 않아도 기본값이 적용 됩니다.

function Welcome({ name }) {
  return <div>{name}</div>
}

Welcome.defaultProps = {
  name: 'Hello World'
}

기본값 설정과 유사한 방법으로 Props의 타입을 지정할 수 있습니다. 이 방법을 사용하기 위해서는 prop-types를 import 하여야 합니다.

import PropTypes from 'prop-types';

function Welcome({ name }) {
  return <div>{name}</div>
}

Welcome.propTypes = {
  name: PropTypes.string
}

PropTypes의 타입은 아래와 같습니다(일부).

  • array
  • bool
  • func
  • number
  • object
  • string
  • instanceOf(클래스)
  • oneOf([]) : 주어진 배열 요소중 값 하나
  • oneOfType([React.PropTypes.string, React.PropTypes.number]) : 주어진 배열 안 종류 중 하나
  • objectOf(React.PropTypes.number) : 객체의 모든 키 값이 인자로 주어진 PropTypes인 객체
  • any

PropTypes를 이용해서 필수값 여부를 지정할수도 있습니다. 이때 isRequired를 사용합니다.

import PropTypes from 'prop-types';

function Welcome({ name }) {
  return <div>{name}</div>
}

Welcome.propTypes = {
  name: PropTypes.string.isRequired
}

defaultPropsPropTypes 설정은 클래스형 컴포넌트에서도 동일합니다.

State

Props는 부모가 자식에게 값을 지정하는 방법이었습니다. State는 컴포넌트 내부에서 값을 지정하는 방법입니다. 함수형 컴포넌트에서는 useState라는 Hook을 통해서 state를 선언할 수 있습니다.

function Welcome() {
  const [count, setCount] = useState(0);
  return <div>{count}</div>
}

useState를 호출하면 배열을 반환해줍니다. 첫번째값은 state, 두번째 값은 state 값을 변경 시킬 세터입니다. state는 직접 값을 수정하지 않고 세터를 통해서 값을 변경하여야 합니다. 그래서 값이 변경된 것을 리액트에서 추적할 수 있습니다.

function Button() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>버튼</button>
    <p>{count}</p>
  )
}

세터를 통해서 값을 변경하더라도 리액트는 즉각 값을 업데이트 하지 않습니다. 세터는 비동기적으로 호출이 되어 집니다. 이는 state가 업데이트 되면 리렌더링이 발생하는데 동기적으로 작동을 하게 되면 너무 잦은 리렌더링이 발생하기 때문에 성능 향상을 위해 비동기적으로 작동하게 됩니다.

아래처럼 버튼을 클릭했을 때 출력 결과는 1이 됩니다. 세터가 비동기적으로 작동하기 때문에 두번째 세터를 호출 할때의 count는 값이 업데이트 되지 않아 0이기 때문입니다.

function Button() {
  const [count, setCount] = useState(0);
  const onClick = () => {
    setCount(count + 1);
    setCount(count + 1);
  }
  return (
    <button onClick={onClick}>버튼</button>
    <p>{count}</p>
  )
}

그래서 위와 같은 문제를 해결하기 위해서는 세터에 함수를 넘겨주면 됩니다. 첫번째 파라미터로 이전 state 값을 넘겨주고 있고, return으로 변경하고자 하는 값을 반환하면 됩니다.

function Button() {
  const [count, setCount] = useState(0);
  const onClick = () => {
    setCount((prev) => prev + 1);
    setCount((prev) => prev + 1);
  }
  return (
    <button onClick={onClick}>버튼</button>
    <p>{count}</p>
  )
}

0개의 댓글