본문 바로가기
TIL/Code States

Code States 20일차 - React State & Props

by 죠르띠에 2021. 8. 13.

Props

Props의 특징

  • 컴포넌트의 속성(property)을 의미한다.
    props는 성별이나 이름처럼 변하지 않는 외부로부터 전달받은 값으로, 웹 어플리케이션에서 해당 컴포넌트가 가진 속성에 해당합니다.
  • 부모 컴포넌트(상위 컴포넌트)로부터 전달받은 값이다.
    React 컴포넌트는 JavaScript 함수와 클래스로, props를 함수의 전달인자(arguments)처럼 전달받아 이를 기반으로 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반한다. 따라서, 컴포넌트가 최초 렌더링될 때에 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용할 수 있다.
  • 객체 형태이다.
    props로 어떤 타입의 값도 넣어 전달할 수 있도록 props는 객체의 형태를 가진다.
  • props는 읽기 전용이다.
    props는 성별이나 이름처럼 외부로부터 전달받아 변하지 않는 값이다. 그래서 props는 함부로 변경될 수 없는 읽기 전용(read-only) 객체가 되었다. 함부로 변경되지 않아야 하기 때문이다.
읽기 전용 객체가 아니라면 props를 전달받은 하위 컴포넌트 내에서 props 를 직접 수정 시 props를 전달한 상위 컴포넌트의 값에 영향을 미칠 수 있게 된다. 즉, 개발자가 의도하지 않은 side effect가 생기게 되고 이는 React의 단방향, 하향식 데이터 흐름 원칙(React is all about one-way data flow down the component hierarchy)에 위배된다.

How to use props

props를 사용하는 방법은 아래와 같이 3단계 순서로 나눌 수 있다.

  1. 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
  2. props를 이용하여 정의된 값과 속성을 전달한다.
  3. 전달받은 props를 렌더링한다.

위 단계에 맞추어 props를 사용하기 위해 우선 <Parent><Child> 라는 컴포넌트를 선언하고, <Parent> 컴포넌트 안에 <Child> 컴포넌트를 작성한다.

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child />
    </div>
  );
};

function Child() {
  return (
    <div className="child"></div>
  );
};

컴포넌트를 만들었으니 이제 전달하고자 하는 속성을 정의해 본다. HTML에서 속성과 값을 할당하는 방법과 같다.

<a href="www.codestates.com">Click me to visit Code States</a>

React 에서 속성 및 값을 할당하는 방법도 이와 유사하다. 다만, 전달하고자 하는 값을 중괄호 {} 를 이용하여 감싸주면 된다.

<Child attribute={value} />

위 방법을 이용하여 text 라는 속성을 선언하고, 이 속성에 "I'm the eldest child"라는 문자열 값을 할당하여 <Child> 컴포넌트에 전달해 본다.

<Child text={"I'm the eldest child"} />

이제 <Parent> 컴포넌트에서 전달한 "I'm the eldest child"라는 문자열을 <Child> 컴포넌트에서 받아 본다. 방법은 간단하다. 함수에 인자를 전달하듯이 React 컴포넌트에 props 를 전달하면 되고, 이 props 가 필요한 모든 데이터를 가지고 오게 된다.

function Child(props) {
  return (
    <div className="child"></div>
  );
};

props를 전달 받았으니, 마지막으로 이 props 를 렌더링해 본다. props 를 렌더링하려면 JSX 안에 직접 불러서 사용하면 된다. 다만, props 는 객체라고 하였고, 이 객체의 { key : value }<Parent> 컴포넌트에서 정의한 { attribute : value } 의 형태를 띠게 된다. 따라서 JavaScript 에서 객체의 value 에 접근할 때 dot notation 을 사용하는 것과 동일하게 props 의 value 또한 dot notation 으로 접근할 수 있다. 아래와 같이 props.text를 JSX에 중괄호와 함께 작성하면 잘 작동한다.

function Child(props) {
  return (
    <div className="child">
      <p>{props.text}</p>
    </div>
  );
};

 

props.children

props 를 전달하는 또 다른 방법으로 여는 태그와 닫는 태그의 사이에 value 를 넣어 전달할 수 있다. 이 경우 props.children 을 이용하면 해당 value 에 접근하여 사용할 수 있다.

function Parent() {
  return (
    <div className="parent">
        <h1>I'm the parent</h1>
        <Child>I'm the eldest child</Child>
    </div>
  );
};

function Child(props) {
  return (
    <div className="child">
        <p>{props.children}</p>
    </div>
  );
};

State

State hook, useState

useState 사용법

React에서는 state 를 다루는 방법 중 하나로 useState 라는 특별한 함수를 제공합니다. 이 함수의 사용 방법과 작동 방식을 위의 체크박스 예로 들어 살펴보겠다.

 

  • useState 를 이용하기 위해서는 React로부터 useState 를 불러와야 한다. import 키워드로 useState 를 불러온다.
import { useState } from "react";
  • 이후 useState 를 컴포넌트 안에서 호출해 준다. useState 를 호출한다는 것은 "state" 라는 변수를 선언하는 것과 같으며, 이 변수의 이름은 아무 이름으로 지어도 된다. 일반적인 변수는 함수가 끝날 때 사라지지만, state 변수는 React에 의해 함수가 끝나도 사라지지 않는다.
  • 문법적으로 보면 아래 예시의 isChecked, setIsCheckeduseState 의 리턴값을 구조 분해 할당한 변수이다.
function CheckboxExample() {
  // 1번 코드를 풀어쓰면
  const [isChecked, setIsChecked] = useState(false); // 1번

  //...

  // 2번 코드와 같습니다.
  const stateHookArray = useState(false); // 2번
  const isChecked = stateHookArray[0];
  const setIsChecked = stateHookArray[1];
}
  • useState 를 호출하면 배열을 반환하는데, 배열의 0번째 요소는 현재 state 변수이고, 1번째 요소는 이 변수를 갱신할 수 있는 함수이다. useState 의 인자로 넘겨주는 값은 state의 초기값이다.
const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
  • 이 state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용하면 된다. 여기서는 isChecked 가 boolean 값을 가지기 때문에 true or false 여부에 따라 다른 결과가 보이도록 삼항연산자를 사용한다.
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>

 

State 갱신하기

사용자가 체크박스 값을 변경하면 onChange 이벤트가 이벤트 핸들러 함수인 handleChecked 를 호출하고, 이 함수가 setIsChecked 를 호출하게 된다. setIsChecked 가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되며, React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링 한다.

function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);

  const handleChecked = (event) => {
    setIsChecked(event.target.checked);
  };

  return (
    <div className="App">
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
    </div>
  );
}

state hook 사용 시 주의점

  • React 컴포넌트는 state가 변경되면 새롭게 호출되고, 리렌더링 된다.
  • React state는 상태 변경 함수 호출로 변경해야 한다. 강제로 변경을 시도하면 안 된다. 상태 변경 함수 사용은 React와 개발자의 약속이기 때문에 지켜주셔야 한다. 강제로 변경을 시도하면, 리렌더링이 되지 않는다거나, state가 제대로 변경되지 않는다.

 

React 이벤트 처리

React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사하다. 단, 몇 가지 문법 차이가 있다.

  • React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용한다.
  • JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달한다.
<!-- HTML의 이벤트 처리 방식 -->
<button onclick="handleEvent()">Event</button>

<!-- React의 이벤트 처리 방식 -->
<button onClick={handleEvent}>Event</button>

 

React 데이터 흐름

React의 개발 방식의 가장 큰 특징은 페이지 단위가 아닌, 컴포넌트 단위로 시작한다는 점이 가장 큰 특징이다. 먼저 컴포넌트를 만들고, 다시 페이지를 조립해나간다. 즉, 상향식(bottom-up)으로 앱을 만든다. 이것의 가장 큰 장점은 테스트가 쉽고 확장성이 좋다.

컴포넌트는 단일 책임 원칙에 따라 구분한다. 하나의 컴포넌트는 한가지 일만 한다.

컴포넌트는 컴포넌트 바깥에서 props를 이용해 데이터를 마치 인자(arguments) 혹은 속성(attibutes)처럼 전달 받을 수 있다. 즉 데이터를 전달하는 주체는 부모 컴포넌트가 된다. 이는 데이터 흐름이 하향식임(top-down)을 의미한다.

이 원칙은 매우 중요하다. 얼마나 중요하냐면, 단방향 데이터 흐름(one-way data flow)이라는 키워드가 React를 대표하는 설명 중 하나일 정도이다. 또한 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못한다.

'TIL > Code States' 카테고리의 다른 글

Code States 26일차 - 재귀  (0) 2021.08.24
Code States 25일차 - 객체 지향 JavaScript  (0) 2021.08.23
Code States 19일차 - React Router  (0) 2021.08.12
Code States 19일차 - React SPA  (0) 2021.08.12
Code States 18일차 - React 기초  (0) 2021.08.11