본문 바로가기

개발인생다반사/TIL(Today i learned)

TIL 211020 - [React] 데이터 흐름의 이해와 비동기 요청 처리

Achievement Goals

React 데이터 흐름

  • React에서의 데이터 흐름, 단방향 데이터 흐름을 이해할 수 있다.
  • 어떤 컴포넌트에 state가 위치해야 하는지 알 수 있다.
  • State 끌어올리기의 개념을 이해할 수 있다.
    • 상태 변경 함수가 정의된 컴포넌트와, 상태 변경 함수를 호출하는 컴포넌트가 다름을 알 수 있다.

Effect Hook

  • Side effect가 어떤 의미인지 알 수 있다.
  • React 컴포넌트를 만들 때 side effect로부터 분리해서 생각할 수 있다. (비즈니스 로직과 표현 영역 구분)
    • Side effect의 예를 들 수 있다.
  • Effect Hook을 이용해 비동기 호출 및 AJAX 요청과 같은 side effect를 React 컴포넌트 내에서 처리할 수 있다.
  • Effect Hook에서의 dependency array 사용법을 이해할 수 있다.
  • 컴포넌트 내에서 네트워크 요청시, 로딩 화면과 같이 보다 나은 UI를 만드는 법을 이해할 수 있다.

Chapter 1 - React 데이터 흐름

(1) React에서의 데이터 흐름

웹페이지를 컴포넌트로 생각하기

"데이터는 아래로 흐릅니다." 단방향 데이터 흐름(One-way data flow)

부모 컴포넌트나 자식 컴포넌트는 특정 컴포넌트의 상태에 대해 알 수도 없고 관심 가질 필요 없음.

그래서 state는 캡슐화 로컬이라 불림. state가 소유하고 설정한 컴포넌트 이외에는 어떠한 컴포넌트도 접근할 수 없음

 

컴포넌트는 자신의 state를 자식 컴포넌트에 props로 전달.

자식 컴포넌트는 이것이 어디서 왔는지 알지 못함.

이를 '하향식', '단방향식' 데이터 흐름이라고 합니다.

각 Clock은 독립적으로 작동한다.

 

React로 사고하기

컴포넌트를 설계할때 단일 책임원칙 준수(한개의 컴포넌트는 한개의 기능만 가짐)

 

1단계: UI를 컴포넌트 계층 구조로 나누기

상향식으로 만듦. 테스트가 쉽고 확장성 좋음, 트리 구조

 

<Header>, <Search>, <Link>, <NewTweetForm>, <SingleTweet>

<Twittler>

  <NewTweetForm>

  <Tweets>

      <SingleTweet>

       <SingleTweet>

 

2단계: React로 정적인 버전 만들기

앱의 정적 버전 만들기(초기 작업). 데이터 모델을 가지고 UI를 렌더링은 되지만 아무 동작도 없는 버전 제작.

props만 생각하기. state를 사용하지 말기. state는 상호작용을 위해(시간이 지남에 따라 데이터가 바뀌는데)

사용. 간단한 앱을 만들 때는 하향식이 좋지만 프로젝트가 커지면 상향식으로.

3단계: UI state에 대한 최소한의(하지만 완전한) 표현 찾아내기

UI 상호작용을 위해 데이터 모델을 변경할 수 있는 방법을 찾아라.

앱이 필요로 하는 최소한의 state 집합 생각(중복 배제)

 

state 여부 판단기준

1. 부모로 부터 props 받는지 (받는다 그렇다면 state 아님)

2. 시간이 지나도 변하지 않는지 (변하지 않는다 그렇다면 state 아님)

3. 다른 컴포넌트들의 state, props로 계산 가능한지 (계산이 가능하다 그렇다면 state아님)

 

4단계: State 위치 정하기(가장 어려운 부분)

하나의 상태를 기반으로 두 컴포넌트가 영향을 받는다면 공통 소유 컴포넌트를 찾아 그곳에 상태를 위치해야 한다.

 

5단계 역방향 데이터 흐름 추가하기

상태 위치 정하고 난뒤 부모 컴포넌트의 상태가 하위 컴포넌트에 의해 변하는 경우가 있음

(새로운 트위 추가 경우, 버튼을 통해 이 액션은 부모의 상태를 변화시켜야 함)

이를 해결하는 방법이 "State 끌어올리기(Lifting state up")

상태를 변경시키는 함수(handler)를 하위 컴포넌트에 props로 전달해서 해결 가능

(2) State 끌어올리기

역방향 데이터 흐름 문제 해결

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

 

부모 컴포넌트의 handleChagneVale 함수를 자식 컴포넌트에 props로 전달하여

setValue 변경하였음.

 

혹은 설정할 값을 콜백 함수의 인자로 넘길 수도 있다.

Chapter 2 - Effect Hook

(1) Side Effect(부수 효과)

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

Pure Function(순수 함수) : 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수. 예측 가능한 함수

함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우. 순수함수라고 할 수 없음.

순수함수는 입력으로 전달된 값을 수정하지 않는다. 그래서 네트워크 요청과 같은 Side Effect가 없다.

순수함수는 어떤 전달 인자가 주어질 경우, 항상 똑같은 값이 리턴됨을 보장한다.

 

Math.random()은 순수함수가 아니다. 호출할 때마다 결과값이 바뀌기 때문.

fetch API를 통한 Ajax요청도 순수함수가 아니다. 서버 데이터에 side Effect 가능. 처리 과정에 오류 가능

 

React의 함수 컴포넌트는 Side Effect가 없는 순수함수로 작동.

그러나 React와 상관없는 AJAX 요청, LocalStorae, 타이머API는 React와 상관없어서 

React 입장에서 SideEffect이다. React는 Side Effect를 다루기 위해 Effect Hook를 제공

 

React 컴포넌트에서의 Side Effect

  • 타이머 사용 (setTimeout)
  • 데이터 가져오기 (fetch API, localStorage)=

(2) Effect Hook(1) - 기본

useEffect는 컴포넌트 내에서 Side Effect를 실행할 수 있게 하는 Hook이다.

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

export default function App() {
  const proverbs = [
    "좌절감으로 배움을 늦추지 마라",
    "Stay hungry, Stay foolish",
    "Memento Mori",
    "Carpe diem",
    "배움에는 끝이 없다"
  ];
  const [idx, setIdx] = useState(0);

  const handleClick = () => {
    setIdx(idx === proverbs.length - 1 ? 0 : idx + 1);
  };

  return (
    <div className="App">
      <button onClick={handleClick}>명언 제조</button>
      <Proverb saying={proverbs[idx]} />
    </div>
  );
}

function Proverb({ saying }) {
  useEffect(() => {
    document.title = saying;
  });
  return (
    <div>
      <h3>오늘의 명언</h3>
      <div>{saying}</div>
    </div>
  );
}

useEffect는 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook이다.

아래에서 확인할 수 있듯이 이 컴포넌트의 Side Effect는 브라우저 API를 이용하여 타이틀을 변경하는 것이다.

기본적인 useEffect를 사용한 함수

useEffect가 실행되는 시점

  • 컴포넌트 생성 후 처음 화면에 렌더링(표시)
  • 컴포넌트에 새로운 props가 전달되며 렌더링
  • 컴포넌트에 상태(state)가 바뀌며 렌더링

Hook을 쓸 때 주의할 점

  • 최상위에서만 Hook을 호출합니다. ==> 이 규칙을 따르면 컴포넌트가 렌더링 될때마다 항상 동일 순서로 Hook이 호출
  • React 함수 내에서 Hook을 호출합니다. ==> 일반적인 JS 함수에 호출 금지

(3)Effect Hook(2) - 조건부 실행

useEffect의 두번째 인자는 배열. 배열은 조건을 담고 있고 여기서의 조건은 boolean형태의 표현식이 아닌,

어떤 값의 변경이 일어날 때를 의미. 배열에 어떤 값의 목록이 들어가고 이 배열을 특별히 종속 배열이라고 칭함

조건부 useEffet 사용

useEffect의 두번째 인자 종속성 배열, 배열 내의 종속성1, 종속성2의 값이 변할 대 첫번째 인자의 함수가 실행됨

useEffect(함수, [종속성1, 종속성2, ...])

 

단 한번만 실행되는 Effect 함수

1. 빈 배열 넣기

- 빈 배열을 2번째 인자로 사용하는 경우 컴포넌트가 처음 생성될 때만 effect함수가 실행.

- 외부 API를 통해 리소스 받아오고 더 이상 API호출이 필요없을 때

useEffect(함수, [])

2. 아무것도 넣지 않기 (기본 형태)

- 컴포넌트 처음 렌더링될 때 props가 업데이트 될때, state(상태)가 업데이트 될때 실행

useEffect(함수)

 

 

(4) 컴포넌트 내에서 AJAX 요청

목록 내에서 필터링 구현

  1. 컴포넌트 내에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter 하는 방법
  2. 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청을 할 때, 필터링한 결과를 받아오는 방법 (보통, 서버에 매번 검색어와 함께 요청하는 경우가 이에 해당합니다)

장점단점

  장점 단점
컴포넌트 내부에서 처리 HTTP 요청의 빈도를 줄일 수 있다 브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트의 부담이 늘어난다
컴포넌트 외부에서 처리 클라이언트가 필터링 구현을 생각하지 않아도 된다 빈번한 HTTP 요청이 일어나게 되며, 서버가 필터링을 처리하므로 서버가 부담을 가져간다