[CS] React 데이터 흐름 Day-30

cptkuk91·2021년 11월 23일
0

CS

목록 보기
57/139

React 데이터 흐름

React의 개발 방식의 가장 큰 특징은 페이지 단위가 아닌, 컴포넌트 단위로 시작하는 것입니다.

상향식(bottom-up)으로 앱을 만듭니다. 가장 큰 장점은 테스트가 쉽고 확장성이 좋습니다.(컴포넌트 계층 구조로 나누는 것이 가장 우선순위가 됩니다.)

컴포넌트는 트리 구조입니다.
컴포넌트 외부에서 props를 이용해 데이터를 인자(arguments) 혹은 속성(attributes)처럼 전달받을 수 있습니다.

데이터를 전달하는 주체는 부모 컴포넌트가 됩니다. 이때 데이터의 흐름은 하향식(top-down)을 의미합니다.

단방향 데이터 흐름(one-way data flow)는 React를 대표하는 설명 중 하나입니다.

변하는 값과, 변하지 않는 값이 있습니다. 사용자 입력에 따라 이벤트가 얼마든지 변할 수 있습니다. 이것을 상태(state)라고 합니다.

모든 데이터를 상태로 둘 필요는 없습니다. 상태는 최소화하는 것이 가장 좋습니다. 상태가 많아질수록 애플리케이션은 무겁고, 복잡해집니다.

  • 부모로부터 props를 통해 전달 됩니까?
    state가 아닙니다.
  • 시간이 지나도 변하지 않나요?
    state가 아닙니다.
  • 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가요?
    state가 아닙니다.

상태의 위치

하나의 상태를 두 컴포넌트가 영향을 받는다면 공통 소유 컴포넌트를 찾아 그 곳에 상태를 위치해야 합니다.
(두 개의 자식 컴포넌트가 하나의 상태에 접근하고자 할 때는 두 자식의 공통 부모 컴포넌트에 상태를 위치해야 합니다.)

하위 컴포넌트가 부모 컴포넌트에 영향을 주는 경우도 있습니다.
클릭 이벤트 발생 후 부모의 상태를 바꿔야하는 상황이라면 State 끌어올리기 (Lifting state up)을 통해
변경할 수 있습니다.

상태를 변경시키는 함수(handler)를 하위 컴포넌트에 props로 전달해 해결할 수 있습니다.

상태 끌어올리기 (Lifting State Up)

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

(상위 컴포넌트는 상태를 변경하는 함수를 하위 컴포넌트에 전달하고, 함수를 하위 컴포넌트가 실행합니다. 그럼 상태가 끌어올려집니다.)

Side Effect (부수 효과)

함수 내에서의 구현이 함수 외부에 영향을 끼치는 경우 Side Effect가 있다고 이야기합니다.

ex)

let study = 'hello';

function hard() {
  study = 'world';
}

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

Pure Function (순수 함수)

오직 함수의 입력만이 함수의 결과에 영향을 주는 함수를 의미합니다. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우, 순수 함수라고 부를 수 없습니다. 또한 순수 함수는, 입력으로 전달된 값을 수정하지 않습니다.

ex)

function upper(str) {
  return str.toUpperCase(); // toUpperCase
}

upper('hello') // 'HELLO'

React의 함수 컴포넌트

React 애플리케이션을 작성할 때에는, AJAX 요청이 필요하거나, LocalStorage 또는 타이머와 같은 React와 상관없는 API를 사용하는 경우가 발생할 수 있습니다. 이는 React의 입장에서 전부 Side Effect 입니다. React Side Effect는 Effect Hook을 사용합니다.

useEffect

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

API

useEffect의 첫번째 인자는 함수입니다.
실행 조건

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

Effect Hook

조건부 effect 발생 (Dependency array)

useEffect의 두 번 째 인자는 배열입니다. 배열은 조건을 담고 있고, 어떤 값의 변경이 일어날 때를 뜻합니다.

Data Fetching:필터링

목록 내 필터링을 구현하기 위해서는 두가지 접근이 있습니다.

  • 컴포넌트 내부에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter하는 방법

처음 단 한 번, 외부 API로 목록을 받아오고, filter 함수를 이용합니다.

  • 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청할 때 필터링한 결과를 받아오는 방법

검색어가 바뀔 때 마다, 외부 API를 호출합니다.

두 방식의 차이점은?

컴포넌트 내부에서 필터링은 HTTP 요청 빈도를 줄일 수 있지만, 브라우저 메모리 상 많은 데이터를 갖게 됨(클라이언트 부담)

컴포넌트 외부에서 필터링은 클라이언트가 필터링 구현을 생각하지 않아도 됩니다. 하지만 HTTP 요청 빈도가 늘어나 서버에 부담이 됩니다.

AJAX 요청

ex) CodeStates 참고 자료

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

fetch API를 사용해, 서버에 요청한다면? 목록을 제공하는 엔드포인트가 http://서버주소/proverbs 라고 가정했을 때 위와 같이 요청하면 된다.

AJAX 요청이 느릴 경우

모든 네트워크 요청이 즉각적인건 아니기 때문에 외부 API 접속이 느릴 경우 로딩 화면(loading indicator)의 구현은 필수적입니다.

로딩 화면 구현에도 상태 처리가 필요합니다.
ex)

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

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

로딩 화면 구현은 fetch 전후에 설정해주면 훌륭한 UX를 구현할 수 있습니다.

useEffect(() => {
  setIsLoading(true);
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
      setIsLoading(false);
    });
}, [filter]);
profile
메일은 매일 확인하고 있습니다. 궁금하신 부분이나 틀린 부분에 대한 지적사항이 있으시다면 언제든 편하게 연락 부탁드려요 :)

0개의 댓글