React - 기초 - 3

2021. 9. 17. 18:28·SE Bootcamp 내용 정리

React State & Props

학습 목표

* state, props의 개념
* React 함수 컴포넌트(React Function Component)에서 state hook을 이용한 state 정의 및 변경
* React 컴포넌트에 props 전달
* 이벤트 핸들러 함수 생성 및 사용
* 실제 웹 애플리케이션의 컴포넌트 분석하기
* 개발시 state와 props의 위치 정하기
* React의 단방향 데이터  흐름(One-way data flow)에 대한 이해

State & Props Intro

Props vs. State(상태)

props는 외부로부터 전달 받은 값
state는 내부에서 변화하는 값(컴포넌트 안에서만 지지고 볶고)

Props & State 구분하기 예제

Props        // 불변 하는 값
* 이름
* 성별

State        // 변할 수 있는 값
* 나이
* 현재 사는 곳
* 취업 여부
* 결혼/연애 여부

Props

Props의 특징

컴포넌트의 속성(property)을 의미함

props는 성별이나 이름처럼 변하지 않는 외부로부터 전달 받은 값
웹 애플리케이션에서 해당 컴포넌트가 가진 속성

부모 컴포넌트(상위 컴포넌트)로부터 전달 받은 값

React 컴포넌트는 자바스크립트 함수와 클래스로 prop를 함수의 전달인자(argument)처럼 전달받아서 이를 기반으로 React 엘리먼트를 반환
→ 컴포넌트가 최초 렌더링 시의 초기값으로 사용 가능

객체 형태

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

사용 방법은 3단계로 구분 가능
 

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

 

위의 단계 연습을 위해 연습용 컴포넌트 <Parent> 와 <Child> 컴포넌트를 선언
 

function Parent() {    //부모 컴포넌트
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child />    // 부모 컴포넌트 안에 자식 컴포넌트를 작성
    </div>
  );
};

function Child() {        //자식 컴포넌트    
  return (
    <div className="child"></div>
  );
};

 

1.전달하고자 하는 속성과 값(data)을 정의
전달하고자 하는 값을 중괄호 {}를 이용하여 감싸준다

 

기본문법

<Child attribute={value} />

 
기본문법을 이용하여 text라는 속성을 선언하고, 이 속성에 “I’m not child” 문자열 값(data)을 할당하여 <Child> 컴포넌트에 전달

 

ex) 부모 컴포넌트인 <Parent> 컴포넌트 내에서 작성

<Child text={“I’m not child”} />

 

2.props를 이용하여 정의된 값과 속성을 전달
<Parent> 컴포넌트에서 전달한 문자열을 <Child> 컴포넌트에서 받아보자
→ 함수에 인자를 전달하듯이 React 컴포넌트에 props를 전달하면 이 props가 필요한 모든 데이터를 가지고 옴

 

ex) <Child> 컴포넌트에서 props 매개변수 사용 예시

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

};

 

3.전달받은 props를 렌더링
props를 렌더링하려면 JSX 안에 직접 불러서 사용
→ 객체 형태이므로 컴포넌트에서 정의한 { attribute : value } 의 형태
→ 즉, dot notation 같은 거 이용해서 표현 가능(단, { } 이용)
 

ex) <Child> 컴포넌트에서 props.text 렌더링 예시

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

};

props.children

props를 전달하는 또 다른 방법으로 여는 태그와 닫는 태그 사이에 value를 넣어 전달 가능
→ 이 경우 props.children 로 해당 value에 접근하여 사용 가능
 

ex) props.children 사용 예시


function Parent() {
  return (
    <div className="parent">
        <h1>I'm the parent</h1>
        <Child>I'm the eldest child</Child>    // 여는 태그와 닫는 태그 사이에 value 작성
    </div>
  );
};

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

State

애플리케이션의 “상태”

컴포넌트 내부에서 변할 수 있는 값
→ 쇼핑몰 장바구니를 예로 들어 장바구니 내에서의 상태로 구분하면
check된 상태
check되지 않은 상태
 

체크 여부에 따라 구매할 물건의 개수와 금액이 변경되고 이에 따라 사용자 화면도 달라짐
→ 이처럼 컴포넌트 내에서 변할 수 있는 값인 상태는 React state로 취급

State hook, useState

useState 사용법

React에서는 state를 다루는 용도로 useState라는 함수를 제공
 

1.useState를 이용하기 위해 React로부터 불러와야 함. Import 시키는 것
 

import {useState} from “react”;

 
2.useState를 컴포넌트 안에서 호출
→ useState를 호출하는 것은 “state”라는 변수를 선언하는 것과 같다
→ 일반적인 변수는 함수가 끝날 때 사라지지만 state 변수는 React에 의해 함수가 끝나도 사라지지 않는다
 

ex) useState 문법 예

function CheckboxExample() {
// 새로운 state 변수를 선언하고, 여기서는 이것을 isChecked 라 이름 지음
  const [isChecked, setIsChecked] = useState(false);

// 문법적으로는 isChecked, setIsChecked는 useState의 리턴값을 구조 분해 할당한 변수

// 위의 코드를 풀어 쓴 것
  const stateHookArray = useState(false);
  const isChecked = stateHookArray[0];
  const setIsChecked = stateHookArray[1];

 

3.useState를 호출하면 배열을 반환하는데 배열의 0번째 요소는 현재 state 변수이고, 1번째 요소는 이 변수를 갱신할 수 있는 함수이다
→ useState의 인자로 넘겨주는 값은 state의 초기값
 

useState의 수도코드

const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);

 
위의 수도코드를 이용해 실제 코드 작성을 해보면
 

function CheckboxEx(){
    const [isChecked, SetIsChecked] = useState(false);
}

&#160
→ 여기서 useState 함수가 state hook에 해당함

&#160
4.state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용하면 됨
→ 위의 예시에서는 boolean 값을 가지므로 삼항 연산자를 사용해서 해보겠음
 

<span>{isChecked? “Checked” : “UnChecked”}</span>

state 갱신하기

위의 예시에서 state를 갱신하기 위해 갱신용 함수인 setIsChecked를 호출
→ input [type=checkbox] JSX 엘리먼트의 값 변경에 따라 isChecked가 변경되게 해야함. 브라우저에서 checked로 값이 변경되면 React의 isChecked도 변경되어야 함

 
React에서도 마찬가지 로직으로 사용자가 체크박스 값을 변경하면 onChange 이벤트가 이벤트 핸들러 함수(작성한 f)를 호출하고 이 함수가 갱신 함수(setIsChecked)를 호출
 
→ 갱신 함수가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되고 React는 새로운 isChecked 변수를 CheckboxEx 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링함
 

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

  const handleChecked = (event) => {    // 이벤트 핸들러 함수
    setIsChecked(event.target.checked);
  };

  return (
    <div className="App">
      <input type="checkbox" checked={isChecked}    // 사용자가 체크박스 값 변경 onChange={handleChecked} />    //onChange 이벤트로 이벤트 핸들러 함수 호출
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
    </div>
  );
}

주의점

React 컴포넌트는 state(상태)가 변경되면 새롭게 호출되고 리렌더링 되는 구조

 
React State는 상태 변경 함수 호출(갱신용 함수 호출)로 변경해야 한다
→ 강제로 변경을 시도하면 안된다. 이는 규칙이라 보면 됨
→ 강제로 변경을 하면 리렌더링이 되지 않거나 state가 정상 반영 안됨

이벤트 처리 Hands-on 실습

React의 이벤트 처리(이벤트 핸들링) 방식은 DOM의 방식과 유사하나 몇 가지 문법 차이가 있음

* React에서 이벤트는 소문자 대신 카멜 케이스(camelCase)를 사용

* JSX를 사용하여 문자열이 아닌 함수로 이벤트에 이벤트 처리 함수(이벤트 핸들러)를 전달

 

예시) HTML에서의 이벤트 처리 방식

<button onclick="handleEvent()">Event</button>    // onclick 이벤트가 전부 소문자

예시) React에서의 이벤트 처리 방식

<button onClick={handleEvent}>Event</button>    // onClick 이벤트가 카멜 케이스

 

자주 사용되는 이벤트 처리에 대한 예시들

onChange

<input>, <textarea>, <select>와 같은 폼 엘리먼트는 사용자의 입력값을 제어하는데 사용하는데 React에서는 이런 변경될 수 있는 입력값을 컴포넌트 state로 관리하고 업데이트 함

 

ex) onChange 이벤트를 사용한 함수

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {    // 이벤트 핸들러 함수
    setName(e.target.value);    //이벤트가 발생하면 value값을 갱신
  }

  return (
    <div>
      <input type="text" value={name} onChange={handleChange}></input>
      <h1>{name}</h1>
    </div>
  )
};

onClick

사용자가 클릭이라는 행동을 했을 때 발생하는 이벤트
→ 버튼이나 <a> 태그를 통한 링크 이동 같이 사용자의 행동에 따라 애플리케이션이 반응할 때 주로 사용
 

단, onClick 이벤트에 특정 함수 호출 시 바로 호출하면 안 된다
→ 바로 호출하면 렌더링될 때 함수 자체가 아닌 함수 호출의 결과가 onClick에 적용된다(즉, undefined)
→ 그러므로 onClick 이벤트에 함수를 전달할 때는 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의해서 이벤트에 그 함수 자체를 전달해야 함
 
또한 이 때 반드시 화살표 함수 방식 을 사용해야 한다
 

// 함수 정의하기 : 1번째 방법

return (
  <div>
    ...
    <button onClick={() => alert(name)}>Button</button>
    ...
  </div>
  );
};

// 함수 자체를 전달하기: 2번째 방법

const handleClick = () => {
  alert(name);
};

return (
  <div>
      ...
    <button onClick={handleClick}>Button</button>
      ...
  </div>
  );
};

<select>

select 태그는 사용자가 drop down 목록을 열어 그 중 한가지 옵션을 선택하면 선택된 옵션이 state 변수에 갱신 됨

pop up

pop up은 open과 close를 state를 통해 관리 할 수 있음
 

import React, { useState } from "react";
import "./styles.css";

function App() {
  const [showPopup, setShowPopup] = useState(false);

  const togglePopup = (event) => {
    // Pop up 의 open/close 상태에 따라
    // 현재 state 가 업데이트

      setShowPopup(!showPopup);    // showPopup의 값 변화에 따라 바뀌도록(true/false)

    console.log(event);
  };

  return (
    <div className="App">
      <h1>Fix me to open Pop Up</h1>
      {/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
          button tag를 완성 */}
      <button className="open" onClick={togglePopup}>
        Open me
      </button>
      {showPopup ? (
        <div className="popup">
          <div className="popup_inner">
            <h2>Success!</h2>
            <button className="close" onClick={togglePopup}>
              Close me
            </button>
          </div>
        </div>
      ) : null}
    </div>
  );
}

export default App;

Contorolled Component Hands-on

React가 state를 통제할 수 있는 컴포넌트를 뜻함
어떤 방식으로 통제?
→ input에 값 입력 시, state도 그때 그때 바뀌는 방식(onChange)
→ 이 변경된 state와 input의 value도 같게 작성해야 함

React 데이터 흐름

React의 개발 방식? 개발은 상향식(bottom-up) 방식

→ 페이지를 만들기 전에 컴포넌트를 먼저 만들고 서서히 큰 형태로 조립해 가는 방식
→ 테스트가 쉽고 확장성이 좋다
→ 실무에서 앱의 디자인(프로토 타입 등)을 받으면 이를 컴포넌트 계층 구조로 나눠서 봐야 함

 

데이터는 위에서 아래로 흐른다

컴포넌트는 컴포넌트 바깥에서 props를 이용해 데이터를 마치 인자(argument) 혹은 속성(attribute)처럼 전달받을 수 있다
→ 즉, 데이터를 전달하는 주체는 부모 컴퍼넌트; 데이터 흐름은 하향식(top-down)
→ React는 단방향 데이터 흐름(One-way data flow)를 따른다
→ 컴포넌트는 props를 통해 전달 받은 데이터가 어디서 왔는지 전혀 모른다

데이터 정의

모든 데이터를 상태(state)로 둘 필요는 없다. 사실 상태는 최소화하는 것이 좋다(복잡성 때문)
어떤 데이터를 상태(state)로 두어야 하는가?
 

* 부모로부터 props를 통해 전달되는가?    // 맞으면 확실히 state가 아니다

* 시간이 지나도 변하지 않는가?            // 맞으면 확실히 state가 아니다

* 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가?    // 맞으면 state가 아니다(확실까진x)

상태 위치 정하기

두 개의 서로 다른 컴포넌트가 하나의 특정 상태에 의존적일(영향받을) 경우?
→ 두 개의 자식 컴포넌트를 소유하는 공통 부모 컴포넌트에 상태를 위치!

 

이처럼 React에서 데이터를 다룰 때는 컴포넌트 간의 상호 관계와 데이터의 역할, 데이터의 흐름을 고려하여 상태의 위치를 정해야 한다

Checkpoint

useState는 state를 함수 컴포넌트 안에서 사용할 수 있게 해주는 state hook 이다
→ useState를 사용해서 새로운 state를 선언할 때는 주로 배열[]로 구조 분해 할당해서 사용
 

컴포넌트에 useState를 두 개 쓸 수도 있고, useState 초기 값에 객체 형 으로도 넣을 수 있다
 
useState는 함수이다!
 

const [state 저장 변수, state 갱신 함수 ] = useState(상태 초기값);

 

props 전달 방법(부모 컴포넌트가 자식 컴포넌트로 값을 전달해 주는 방식)
 

//    1번 방법
<Component attribute={value1} attribute={value2}>
// 자식 컴포넌트의 파라미터에 props를 “객체 형태”로 전달함
// value가 문자열인 경우 {}를 생략해도 된다
=> {attribute : value}
=> props.attribute

//    2번 방법
<Component>태그와 태그 사이에도 전달 가능함</Component>
=> props.children    // 2번 방식에서는 이 명령어로 받아야 함

 
화살표 함수의 경우 내용이 리턴문 하나 뿐일 때 return 과 감싸는 { }를 생략 가능
 

const Say= () => <Hello name={“kim”} />
                            // return 과 { }를 생략 가능

 

전개 연산자(…) 는 감싸고 있는 것을 한 꺼풀 벗겨 주는 역할을 한다
 

function Say() {
  const userInfo = {
    name: "walli"
  };
  return <Hello {...userInfo} />;        // userInfo를 감싼 { } 를 벗겨줘서 안의 객체가 바로 뜸? 
}

 

props 입장에서는 객체가 아니라 객체를 감싸줘야 이를 전달하는 값이라고 인식한다
 

const Say = () => <Hello props={name: "walli"} />    // 틀린 문법

const Say = () => <Hello props={{name: "walli"}} /> // 굳이 쓰자면 감싸줘야 함
//  그러나 이름 자체가 props는 안쓰는 것을 추천

 

* PascalCase: 앞이 대문자로 시작
* camelCase: 중간에 낙타 혹처럼 대문자
* snake_case: 소문자 표현(단어 간 연결은 _)

 


'SE Bootcamp 내용 정리' 카테고리의 다른 글

React - 보충 학습 1: 부모/자식 컴포넌트, map 메소드, props  (0) 2021.09.30
SECTION 1 회고  (0) 2021.09.30
React - 기초 - 2  (0) 2021.09.16
React – 기초  (0) 2021.09.15
js/node – 고차 함수  (0) 2021.09.15
'SE Bootcamp 내용 정리' 카테고리의 다른 글
  • React - 보충 학습 1: 부모/자식 컴포넌트, map 메소드, props
  • SECTION 1 회고
  • React - 기초 - 2
  • React – 기초
레실이
레실이
  • 레실이
    레실이의 티스토리
    레실이
  • 전체
    오늘
    어제
    • 분류 전체보기 (86)
      • SE Bootcamp 내용 정리 (63)
      • 알고리즘 연습 (7)
      • Project 주저리 (4)
      • 기술 면접 source (3)
      • 개발 일상 (7)
      • 생성 AI 활용 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    cmarket
    CSS
    DOM
    객체
    데이터베이스
    인증/보안
    ubuntu
    Ajax
    중복 순열
    node.js
    mongoDB
    promise
    node
    state
    IT
    PickAndDrink
    Python
    CSR
    MVC
    자료구조
    알고리즘
    Linux
    문자열
    JavaScript
    ORM
    react
    useRef
    useState
    JS
    CORS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
레실이
React - 기초 - 3
상단으로

티스토리툴바