클라이언트 Ajax 요청

moono·2023년 2월 1일
0

React

목록 보기
5/12
post-thumbnail

React 데이터 흐름

🏁 React 데이터 흐름

React 개발 방식은 페이지 단위가 아닌 컴포넌트 단위로 시작한다.
⇒ 페이지의 프로토타입을 전달 받으면 먼저 컴포넌트를 만들고 페이지를 조립한다.

하나의 컴포넌트는 한 가지의 일만 한다.(단일 책임 원칙)

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

  • 컴포넌트는 바깥에서 props 이용해 데이터를 마지 전달인자(arguments) 혹은 속성(attributes) 처럼 전달받을 수 있다.
    ⇒ 데이터를 전달하는 주체는 부모 컴포넌트가 되며, 데이터 흐름이 하향식 이라는 걸 의미한다. ⇒ 단방향 데이터 흐름

데이터 정의

  1. 애플리케이션에 필요한 데이터가 무엇인지 먼저 정의하기

  2. 변하는 값과 변하지 않는 값 파악하기

    • 이벤트에 따라 얼마든지 변할 수 있는 것은 상태(state)
  3. state를 어떤 데이터로 둬야 할까? 생각하기
    state 최소화하는 것이 좋음
    부모로부터 props를 통해 전달되면 state 아니다!
    시간이 지나도 변하지 않으면 state 아니다!
    컴포넌트 안의 다른 state 나 props를 가지고 계산 가능하면 state 아니다!


🏁 State 끌어올리기

상위 컴포넌트의 상태를 변경하는 함수 그 자체를 하위 컴포넌트에 전달하고 그 함수를 하위 컴포넌트가 실행한다.
⇒ 단방향 데이터 흐름에 맞는 해결방법으로 이걸 상태 끌어올리기 라고 한다.

🏷️ 오늘의 과제(StateAirline Client-Part 1)

Main.js
SetCondition 이라는 state 함수에 search 함수 인자를 넣어서
Search 한테 onSearch 라는 이름의 props에 프로퍼티로 넘겨준다.

Search.js
onSearch를 props로 받아서 (그 props에는 state를 변경하는 함수있으니까) 그걸 써서 다시 올려즈거 Main을 재렌더링한다.

의문🧐
setCondition의 useState는 왜 departure 만 있고, destination은 없지?
⇒ 다음 과제 part 2를 위한 것도 있고, 검색을 할 때 destination 아무것도 입력 안했을 때 전체가 나오기 위해

Search 컴포넌트에서 onSearch 함수를 가져와서 실행시키면 결국 Main의 setCondition이 갱신됨

🏷️ Twittler 예제


🏁 REACT 함수 컴포넌트

➰ Side Effect

React 에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 Side Effect 가 발생했다고 한다.
컴포넌트의 순수함수적인 특징에 위배되는 기능들(네트워크 요청 같은 녀석들)
(함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수는 Side effect 가 있다고 말함)

let foo = "hello"
fimctopm bar() {
  foo = 'world'
}
bar(); // bar 는 side effect 를 발생시킨다.

➰ 순수 함수

오직 함수의 입력만이 함수의 결과에 영향을 주는 함수로 입력으로 전달된 값을 수정하지 않는다.
순수함수에는 네트워크 요청과 같은 side effect가 없다.
동일한 input에 동일한 output
특징 : 어떠한 전달 인자가 주어질 경우 항상 똑같은 값이 리턴됨을 보장 ⇒ 예측 가능한 함수

function upper(str) {
  return str.toUpperCase() // toUpperCase 메소드는 원본을 수정하지 않는다.(immutable)
}
upper('hellp') // HELLO

➰ React 함수 컴포넌트

React 의 함수 컴포넌트는 props 가 입력으로, JSX Element가 출력으로 나간다.
여기에는 side effect도 없고, 순수 함수로 작동한다.
하지만 보통 React를 작성할 때 AJAX요청이 필요하거나, React 와 상관없는 API를 사용하는 경우가 발생할 수 있는데
이건 React 입장에서 전부 side effect 이고,
React 는 side effect 를 다루기 위한 Hook 인 Effect Hook 을 제공한다.

리액트 컴포넌트에서의 side effect : 타이머사용(setTimeout), 데이터 가져오기(fetch API, localStorage)



🏁 useEffect

useEffect 는 컴포넌트 내에서 side Effect 를 실행할 수 있게 하는 Hook

useEffect 의 첫번째 인자는 함수이고, 해당 함수 내에서 side effect 를 실행하면 된다.

🧐 언제 실행되지? ⇒ 매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook 이 실행된다.

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

hook 사용 주의할 점

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

JSX가 먼저 실행된 후에 엘리먼트가 렌더링 되고 나서 useEffect가 실행된다


조건부 Effect 발생

useEffect 의 두번째 인자는 배열이고, 조건을 담고 있다.
조건 형태 : 어떠한 값의 변경이 일어날 때 를 의미 ⇒ 어떠한 값의 목록이 들어가고 이걸 종속성 배열(dependency array)이라고 부른다.

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

⇒ 배열 내의 종속성 값이 변할 때, 첫번째 인자의 (effect가 발생하는) 함수가 실행된다.

🏷️ 예제

콘솔창에서 위 예제를 보면 filter가 변할 때만 effect 함수가 실행되는데,(콘솔창 확인하기)
카운트를 올리는 버튼은 컴포넌트의 상태가 바뀌고 업데이트 되지만 effect 함수가 실행되지는 않는다.
⇒ 종속성 배열(dependency array)에는 filter만 존재하고 count는 존재하지 않기 때문
⇒ 🧐 count 도 effect 함수 실행시키려면? 종속성 배열에 count를 추가하기!

한번만 실행되는 Effect 함수

방법

  1. 빈배열 넣기
    ⇒ 종속성 목록에 아무것도 넣지 않는다면 컴포넌트가 처음 생성될 때만 effect 함수가 실행된다.
    대표적으로 외부 API를 통해 리소스를 받아오고 더이상 API 호출이 필요하지 않을 때 사용
useEffect(함수, [])

  1. 아무것도 넣지 않기(기본형태)
    ⇒ 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트 될때 effect 함수가 실행된다.
useEffect(함수)

컴포넌트 내에서의 AJAX 요청

➰ 컴포넌트 내에서 필터링과 컴포넌트 외부에서 필터링의 차이

서버 요청으로 대체가 가능하다.

import { getProverbs } from "./storageUtil"; // storageUtil.js 를 이용해 외부 API 직접 구현(Localstorage API 이용)
장점단점
내부에서 처리HTTP 요청의 빈도를 줄일 수 있다.브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게돼서 클라이언트 부담이 늘어난다.
외부에서 처리클라이언트가 필터링 구현을 생각하지 않아도 된다.빈번한 HTTP요청이 발생해, 서버가 필터링을 처리하므로 서버가 부담을 가진다.

🎶 AJAX 요청을 보내자!

임의로 구현한 위의 storageUtil.js 대신 fetch API 를 써서, 서버에 요청한다면?
(API의 엔드포인트가 http://서버주소/proverbs 라고 가정)

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

🧐 AJAX 요청이 느리면???

외부 API 접속이 느릴 경우를 고려해 로딩화면 구현은 필수!
⇒ React에서는 Ajax 요청 처리할 때, side effect 최소화 위해 Effect Hook을 사용하는데,
만약 사용하지 않고 네트워크 요청하면 그동안 페이지가 멈추거나 깜빡일 수 있다.

기본적인 Loading indicator 구현은 상태처리 가 필요하다.

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

// LoadingIndicator 컴포넌트는 별도로 구현했음을 가정하고 생략
return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}

fetch 요청의 전후로 setIsLoading을 설정해 주어 보다 나은 UX 구현도 가능하다.

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

0개의 댓글