[React] Props, React Hook 개념 학습

Yalstrax·2021년 7월 7일
1

Front End

목록 보기
6/8

React Props, HOOK을 공부한 내용을 바탕으로 정리해보았습니다. 이상한 부분이 있다면 언제든 댓글 달아주세요! 🙆


1. Props 💎

Props는 사람의 성별이나 이름처럼 쉽게 변하지 않는 외부로부터 전달받은 값으로, 현재 컴포넌트가 가진 속성을 의미합니다.

이 Props는 상위 컴포넌트로부터 전달받은 값으로, 현재 컴포넌트는 Props는 Javascript의 함수의 전달인자처럼 전달받습니다.

리턴하는 값은 전달받은 Props를 기반으로 화면에 어떻게 표시될 지를 기술하는 React 엘리먼트입니다.

즉, 컴포넌트가 처음 렌더링될 때, 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용할 수 있습니다.

Props는 객체 형태로 전달합니다. 또한, 쉽게 변하지 않아야하는 값이므로 읽기 전용(Read-only) 객체입니다.

만약, 읽기 전용 객체가 아니라면 Props를 전달받은 현재 컴포넌트에서 Props가 수정될 수 있습니다. 수정된다면, Props를 전달한 상위 컴포넌트에 영향을 끼칩니다.
이는 리액트를 대표하는 원칙인 단방향 데이터 흐름(One Way Data Flow)에 위배됩니다.

리액트는 데이터를 전달하는 주체는 항상 상위 컴포넌트로부터 하위 컴포넌트로, 즉 하향식(Top Down)으로 흐르게 됩니다. 그렇기 때문에, Props는 하위 컴포넌트에서 수정을 방지하기 위해 읽기 전용 객체가 되겠습니다.

Props를 사용하는 방법은 3단계 순서가 있습니다.

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


2. React HOOK ⚓

React는 출시 후 발생했던 다양한 문제들을 해결해왔습니다.
HOOK의 경우, React로 컴포넌트를 작성하고, 유지하면서 발생했던 문제들을 더 쉽게 해결하기 위해 출시된 기술입니다.


HOOK을 사용함으로써, 리액트의 지향점인 함수형 컴포넌트로 State를 관리할 수 있게 되었습니다.

컴포넌트 기반 개발이 가능해지면서, 테스트 및 유지보수가 이전보다 편리해졌고, 사용하기 쉬우며(?) 가독성이 좋은 코드를 만들 수 있게 되었습니다.

또한, 같은 목적의 일을 수행하는 경우, 이전에 사용하던 컴포넌트를 재사용하기도 쉬워졌습니다.

2.1 State 🗽

React 16.8 버전부터 HOOK이 추가되면서, 클래스 컴포넌트에서만 사용할 수 있었던 State를 함수형 컴포넌트에서도 사용할 수 있게 됐습니다.
State는 컴포넌트 내부에서 변할 수 있는 값입니다. 부모로부터 Props를 통해 전달받지 않은 값이며, State가 적용되는 컴포넌트에서만 유의미합니다.
만약, 하나의 State를 기반으로 여러개의 컴포넌트에 영향을 주려면, 그 여러 컴포넌트를 공통으로 소유하는 상위 컴포넌트에 State를 위치해야합니다.

State는 useState를 컴포넌트 내에서 호출하는 것으로 사용할 수 있습니다.

import React, { useState } from "react";

useState를 사용하기 위해 새로운 State를 선언할 때, 보통 첫번째 요소를 현재 State, 두번째 요소에 State를 갱신하는 함수를 배열로 구조 분해 할당하여 사용합니다.

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

위 예제에서 useState가 반환하는 배열의 첫번째 요소인 isChecked가 현재 State, 두번째 요소인 setIsChecked가 State를 갱신하는 함수입니다.

위 예제 처럼, 어떤 특정 조건에 따라 렌더링 여부를 결정해야 할 때, if 조건문 대신 삼항 연산자를 사용합니다.
삼항 연산자의 문법은 { 조건 ? true일 경우 : false일 경우 } 와 같이 사용합니다.

우리 말로 풀어보자면,

이 조건이 참이야? 참이면 이걸 출력할게. 참이 아니라 거짓이면 이걸 출력할게
로 풀 수 있을 것 같습니다.

2.2 Lifting State Up 🤹

리액트의 데이터 흐름은 단방향입니다. 하지만, 역방향 데이터 흐름이 필요할 때가 있습니다. 상위 컴포넌트의 State가 하위 컴포넌트에 의해 변하는 경우입니다.

예를 들면, 우리가 블로그를 포스팅할 때 입니다.

블로그의 홈이 있습니다. 이 홈에선 자신이 작성한 글들을 보여줍니다. 이 공간을 상위 컴포넌트라고 가정하겠습니다.
새 글을 포스팅하기 위해, 작성 내용을 적는 공간은 블로그 홈의 하위 컴포넌트입니다.

하위 컴포넌트에서 글을 작성하고, 포스팅을 하게 되면, 상위 컴포넌트인 블로그 홈에서 새로 포스팅된 글 까지 보여줘야 합니다. 즉, 상위 컴포넌트의 State인 블로그 글 목록을 변화시켜야 합니다.

즉, 하위 컴포넌트에서 발생한 이벤트로, 상위 컴포넌트의 State를 변경해야할 상황입니다.

이를 해결하는 키워드가 State 끌어올리기 (Lifting State Up)입니다.

사용하는 방법은 State를 갱신하는 함수를 하위 컴포넌트에 Props로 전달해서 해결할 수 있습니다. Callback 함수 사용과 비슷합니다.

단방향 데이터 흐름이라는 원칙에 따라, 하위 컴포넌트는 상위 컴포넌트로부터 전달받은 데이터의 형태 혹은 타입이 무엇인지'만' 알 수 있습니다.

데이터가 State로부터 왔는지, 하드코딩으로 입력한 내용인지 알지 못합니다.

그렇기 때문에 하위 컴포넌트에서의 어떤 이벤트로 인해 상위 컴포넌트의 State가 바뀌는 것은 '역방향 데이터 흐름'입니다. 이를 React가 어떻게 해결하는지 제시하고 있습니다.

상위 컴포넌트의 "State를 변경하는 함수" 그 자체를 하위 컴포넌트로 전달하고, 이 함수를 하위 컴포넌트가 실행한다

이는 단방향 데이터 흐름 원칙에 부합하는 해결 방법입니다.

위와 같이 예시를 만들어 보았습니다.

앞서 이야기 했던 블로그 예시 처럼, 기존에 작성되어있던 글들을 상위 컴포넌트가 렌더링합니다.

하위 컴포넌트인 글 작성 공간에서 어떤 이벤트가 발생했을 때, 위 예제에선 새 글 쓰기 이벤트가 실행되었을 때, 이 글을 상위 컴포넌트에도 전달을 해줘야 합니다.

단방향 데이터 흐름 원칙에 위배되지 않기 위해, 상위 컴포넌트에서 글 목록의 State를 갱신하는 함수를 선언하고, 그 함수를 Props로 하위 컴포넌트에 전달합니다.

하위 컴포넌트에서 이벤트(새 글 쓰기) 발생 시, 하위 컴포넌트가 Props로 전달받은 글 목록 State 갱신 함수를 실행하는 것으로 상위 컴포넌트는 갱신된 글 목록 State를 렌더링합니다.

2.3 Effect 🙏

함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우, 해당 함수는 Side Effect가 있다고 말합니다.

let foo = 'hello';

function bar() {
  foo = 'world';
}

bar(); // foo === 'world'

위 예시처럼, bar라는 함수를 실행하면, bar함수 외부에 있는 변수 foo를 변화시킵니다. 즉, 외부에 영향을 끼친 것으로, Side Effect가 발생됐습니다.

외부에 영향을 끼치지 않고, 함수의 입력만이 함수의 결과에 영향을 주는 함수는 순수 함수 입니다. 순수 함수는 Side Effect가 없습니다. 순수 함수의 특징은 어떤 전달 인자가 주어진 경우, 항상 똑같은 값이 반환됩니다. 한마디로, 예측 가능한 함수 입니다.

function upper(str) {
  return str.toUpperCase(); 
  // toUpperCase 메소드는 원본을 수정하지 않습니다 (Immutable)
}
upper('hello') // 'HELLO'

React의 함수형 컴포넌트는 입력 인자로 Props가 들어옵니다. 출력은 JSX Element로 나갑니다. 이는 순수 함수로 작동됩니다.

function SinglePost({ writer, body, createdAt }) { 
  // 입력인자로 Pros 객체가 들어옵니다.
  return <div>
    <div>{writer}</div>
    <div>{createdAt}</div>
    <div>{body}</div>
  </div> // JSX Element가 반환됩니다.
}

그러나, AJAX 요청, 타이머 API 등 React와 상관없는 API를 사용할 경우 Side Effect가 발생합니다.

이 Side Effect를 다루기 위해, React는 Effect HOOK을 제공합니다.

useEffect(함수, 배열) 와 같이 사용할 수 있습니다.
useEffect 는 컴포넌트 내에서 Side Effect를 실행할 수 있게 하는 HOOK 입니다.

useEffect의 첫번째 인자는 함수입니다. 이 함수는 Side Effect를 실행하는 함수입니다.

첫번째 인자로 들어온 함수는 다음과 같은 조건으로 실행됩니다.

  • 컴포넌트 생성 후 처음 화면에 표시될 때
  • 컴포넌트에 새로운 Props가 전달될 때
  • 컴포넌트의 State가 갱신될 때

그리고, useEffect를 사용할 때 주의할 점은

  • 최상위 컴포넌트에서만 useEffect를 호출합니다.
  • React 함수 내에서 useEffect를 호출합니다.

가 있습니다.

useEffect의 두번째 인자는 배열입니다. 이 배열은 조건을 담고 있습니다. 어떤 값의 변경이 일어날 때, useEffect를 실행한다고 생각하면 될 것 같습니다.
배열의 값은 위 어떤 값의 목록이 들어가게 됩니다. 이를 종속성 배열이라 부릅니다.

즉, useEffect에 두번째 인자가 있을 때, 두번째 인자(배열)의 값이 변경될 때에만 useEffect의 첫번째 인자인 함수가 실행됩니다.

만약, useEffect(함수, 빈 배열) 빈 배열을 종속성 배열로 지정한다면 어떻게 될까요?

이 땐, 컴포넌트가 처음 생성될 때만 useEffect 함수가 실행됩니다. 예를 들어, 처음 단 한번, 외부 API를 통해 리소스를 받아오고 더이상 API 호출이 필요하지 않을 때 사용할 수 있습니다.

위 예제처럼, 인풋 태그에서 onChange 이벤트로 filter State의 변화가 생겼을 때, useEffect를 실행하여 노래 목록을 갱신하는 함수를 실행합니다.

이벤트 발생으로 filter State의 변화 이외에, 외부의 노래 목록을 갱신하고자 할 때, 이는 Side Effect이며, Side Effect를 실행하기 위해 useEffect를 사용할 수 있습니다.


React Props와 HOOK 에 대해 제가 공부한 내용을 정리해보았습니다.
긴 글 읽어주셔서 감사드리고, 이상한 부분이 있다면 댓글 부탁드립니다! 감사합니다. 🤗

profile
즐겁다면 그것만으로 만만세!

0개의 댓글