[TSR] React - data flow & 비동기 요청 처리

EllaDev·2022년 2월 3일
0

today-study-record

목록 보기
4/8
post-thumbnail

해당글은 오늘 공부한 내용을 정리하여 메모하는 형식으로 작성한 것으로
설명이나 이해를 돕는 글이 아님을 명시합니다.

Data Flow

React Data Flow

  • 상향식(bottom-up)으로 앱 제작 (컴포넌트 계층 구조로 나누는 것)하면 테스트가 쉽고 확장성이 좋다.
  • 컴포넌트는 단일 책임 원칙(컴포넌트는 한가지 일만 한다.)에 따라 구분한다.
  • 데이터는 위에서 아래로 흐른다.(top down)
  • 단방향 데이터 흐름 (one-way data flow)
  • 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못한다.

State

  • 데이터 값에 따른 분류
    • 변하는 값 : state
    • 변하지 않는 값
  • state는 최소화하는 것이 좋다.
  • 3가지 조건에 부합하지 않아야 state값으로 판단
    • 부모로부터 props를 통해 전달되는가? NO
    • 시간이 지나도 변하지 않나? NO
    • 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가? NO

State 설정 위치

  • 하나의 상태를 기반으로 두 컴포넌트가 영향을 받는다면 공통 소유 컴포넌트(공통 부모)를 찾아 그 곳에 상태를 위치해야한다.
  • 부모 컴포넌트에서의 상태가 하위 컴포넌트에 의해 변하게 된다. 이는 단방향 데이터 흐흠 원칙에 위배된다.
  • 해결할 수 있는 키워드는 바로 "State 끌어올리기(Lifting state up)"이다.

Lifting State Up

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

예제 코드 basic and Twitter 구현



Effect Hook

JS의 문제

  • 호이스팅 : 선언형 함수는 위쪽에서 사용할 수 있다.
    side effect : 내가 이해하지 못한 결과가 나오는것
    순수 함수 : 동일한 결과값이 같음

비동기 작업은 side effect가 생기는 작업이다.

  • Layout 디자인

    쓰로틀 :

Side Effect

  • 함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우
  • 이해하지 못한 결과가 나오는것
  • 비동기 요청(ajax 요청)은 요청에 따른 응답이 일정하지 않기 때문에 side effect가 일어날 수 있다.
let foo = 'hello';

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

bar(); // bar는 Side Effect를 발생시킵니다!

Pure Function

  • 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수
  • 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우는 없다.
  • 입력으로 전달된 값을 수정하지 않는다.
  • 어떠한 전달 인자가 주어질 경우, 항상 똑같은 값이 리턴됨을 보장한다.
  • 예측 가능한 함수이다.
function upper(str) {
  return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않습니다 (Immutable)
}

upper('hello') // 'HELLO'

React 함수 컴포넌트

  • React의 함수 컴포넌트는, props가 입력으로, JSX Element가 출력으로 나간다. 그러므로 side effect가 없는 순수함수이다.
function SingleTweet({ writer, body, createdAt }) {
  return <div>
    <div>{writer}</div>
    <div>{createdAt}</div>
    <div>{body}</div>
  </div>
}

React 컴포넌트에서의 Side Effect

  • 타이머 사용 (setTimeout)
  • 데이터 가져오기 (fetch API, localStorage)
  • React와 상관없는 API를 사용하는 경우가 발생할 수 있다.

Effect Hook

기본

예제 코드

  • useEffect : 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook
    • 첫번째 인자는 함수이다.
  • Side effect : 브라우저 API를 이용하여, 타이틀을 변경하는 것

실행되는 시점

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

주의할 점

  • 최상위에서만 Hook을 호출한다.
  • React 함수 내에서 Hook을 호출한다.

조건부 실행

조건부 effect 발생 (dependency array)

  • useEffect의 두 번째 인자는 배열이다.
    • 조건을 담은 배열으로 boolean 형태의 표현식이 아닌, 어떤값의 변경이 일어날 때를 의미한다.
    • 배열에는 어떤 값의 목록이 들어간다. 이 배열을 종속성 배열이라 부른다.

filter가 변할 때에만, effect 함수가 실행하는 예제

  • 카운트를 올리는 버튼은 컴포넌트의 상태가 바뀌고 업데이트 되지만, 아무리 버튼을 눌러도 effect 함수는 실행되지 않는다. 왜냐하면, 종속성 배열에는 filter만 존재하고, count는 존재하지 않기 때문이다.

  • 카운트 버튼을 눌렀을 때에도 effect 함수를 실행시키려면 어떻게 해야 하나?
    => 조건배열에 couter도 추가하면 된다. [filter, count]

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

    • 배열 내의 종속성1, 또는 종속성2의 값이 변할 때, 첫 번째 인자의 함수가 실행
    • 배열 내의 어떤 값이 변할 때에만, (effect가 발생하는) 함수가 실행

단 한번만 실행되는 Effect 함수

  1. 빈 배열 넣기 : useEffect(함수, [])
  • 컴포넌트가 처음 생성될때만 effect 함수가 실행
  • 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더이상 API 호출이 필요하지 않을 때에 사용
  1. 아무것도 넣지 않기 (기본 형태) : useEffect(함수)
  • useEffect는 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트될 때 effect 함수가 실행

컴포넌트 내에서 AJAX 요청

Data Fetching

목록 내 필터링을 구현하기 위한 두가지 접근
예제 코드

  1. 컴포넌트 내에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter 하는 방법
  • 처음 단 한번, 외부 API로부터 명언 목록을 받아오고, filter 함수를 이용
  1. 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청을 할 때, 필터링한 결과를 받아오는 방법
    (보통, 서버에 매번 검색어와 함께 요청하는 경우가 이에 해당합니다)
  • 검색어가 바뀔 때마다, 외부 API를 호출
장점단점
컴포넌트 내부에서 처리HTTP 요청의 빈도를 줄일 수 있다
컴포넌트 외부에서 처리클라이언트가 필터링 구현을 생각하지 않아도 된다

AJAX 요청

useEffect(() => {
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
    });
}, [filter]);

로딩 구현

const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
  setIsLoading(true);
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
      setIsLoading(false);
    });
}, [filter]);

return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}


More Info

무에서는, 서버의 부담과 클라이언트의 부담이 적절하게 분배된 애플리케이션 구조를 가지게 된다.

클라이언트가 서버에 요청을 덜 보내는 방법
Throttle a series of fetch requests in JavaScript
Throttle, Debounce & Difference

서버가 클라이언트에게 돌려줄 응답을 캐싱하는 방법
HTTP caching

profile
Frontend Developer

0개의 댓글