[S2]Chapter9.[React] 클라이언트 Ajax 요청

React 데이터 흐름
- React의 개발 방식의 가장 큰 특징은 페이지 단위가 아닌, 컴포넌트 단위로 시작한다는 점이 가장 큰 특징

- 페이지를 만들거나 볼 때 컴포넌트단위로 생각하고 다시 페이지 조립해나간다.
- 즉 상향식(bottom-up)으로 앱을 만듭니다.<-가장 큰 장점은 테스트가 쉽고 확장성이 좋습니다.
- 기획자나 PM, 또는 UX 디자이너로부터 앱의 디자인을 전달받고 나면, 이를 컴포넌트 계층 구조로 나누는 것이 가장 먼저 해야 할 일

- 하나의 컴포넌트는 한 가지 일만 합니다.

- 데이터를 어디에 둘지를 결정합니다.

- 컴포넌트는 컴포넌트 바깥에서 props를 이용해 데이터를 마치 전달인자(arguments) 혹은 속성(attributes)처럼 전달받을 수 있습니다.

- 즉 데이터를 전달하는 주체는 부모 컴포넌트가 됩니다. 데이터 흐름이 하향식(top-down)임을 의미합니다.
- 단방향 데이터 흐름(one-way data flow)이라는 키워드가 React를 대표하는 설명 중 하나일 정도입니다.
또한 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못합니다.

- 변하는 갑과 변하지 않는 값을 나눈다.
- 모든 데이터를 상태로 둘 필요는 없습니다. 사실 상태는 최소화하는 것이 가장 좋습니다. 상태가 많아질수록 애플리케이션은 복잡해집니다.

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

- 만일 새 글을 추가하는 이벤트가 발생할 경우, 이때 전체 트윗 목록에 새로운 트윗 객체를 추가할 수 있어야 합니다. 즉, 두 컴포넌트 모두 트윗 목록에 의존합니다.

- 그렇다면, 두 컴포넌트의 부모는 무엇인가요? 바로 Twittler입니다. 전체 트윗 목록 상태는 여기에 위치합시다.

- 바로 새로운 트윗 추가가 대표적인 예죠. 버튼을 통한 이 액션은, 부모의 상태를 변화시켜야 합니다.
- 하위 컴포넌트(NewTweetForm)에서의 클릭 이벤트가, 부모의 상태를 바꾸어야만 하는 상황이 왔습니다. 이를 어떻게 해결할 수 있을까요?
이를 해결할 수 있는 키워드는 바로 "State 끌어올리기(Lifting state up)"입니다.

- 상태를 변경시키는 함수(handler)를 하위 컴포넌트에 props로 전달해서 해결할 수 있습니다. 이는 마치 콜백 함수를 사용하는 방법과 비슷합니다.
State 끌어올리기 (Lifting State Up)
예제

- 상태를 변경하는 함수는 handleChangeValue 입니다. 전달은 props를 이용합시다. props 이름은 적절하게 지어줍시다. 하위 컴포넌트가 버튼 클릭 이벤트에 따라 상태를 변경하려고 하므로 이름은 handleButtonClick이라고 지어줍시다.

- <ChildComponent> 는 마치 고차 함수가 인자로 받은 함수를 실행하듯, props로 전달받은 함수를 컴포넌트 내에서 실행할 수 있게 됩니다. "상태 변경 함수"는 버튼이 클릭할 때 실행되기를 원하므로, 해당 부분에 콜백 함수를 실행합시다.

- 필요에 따라 설정할 값을 콜백 함수의 인자로 넘길 수도 있습니다.
Effect Hook
Side Effect (부수 효과)
- 함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수는 Side Effect가 있다고 이야기합니다. React에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 Side Effect가 발생했다고 말합니다.
예제

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

- 순수 함수에는 네트워크 요청과 같은 Side Effect가 없습니다. 순수 함수의 특징 중 하나는, 어떠한 전달 인자가 주어질 경우, 항상 똑같은 값이 리턴됨을 보장합니다. 그래서 예측 가능한 함수이기도 합니다.
React의 함수 컴포넌트
- 우리가 앞서 배운 React의 함수 컴포넌트는, props가 입력으로, JSX Element가 출력으로 나갑니다. 여기에는 그 어떤 Side Effect도 없으며, 순수 함수로 작동합니다.

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

- useEffect는 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook 입니다. 이 컴포넌트에서 실행하는 Side effect는 브라우저 API를 이용하여, 타이틀을 변경하는 것입니다.
API
- useEffect의 첫 번째 인자는 함수입니다. 해당 함수 내에서 side effect를 실행하면 됩니다.

- 컴포넌트 생성 후 처음 화면에 렌더링(표시)
- 컴포넌트에 새로운 props가 전달되면 렌더링
- 컴포넌트에 상태(state)가 바뀌며 렌더링
- 이와 같이 매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행됩니다.
Hook을 쓸 때 주의할 점
- 최상위에서만 Hook을 호출합니다.
- React 함수 내에서 Hook을 호출합니다.
조건부 effect 발생 (dependency array)
- useEffect의 두 번째 인자는 배열입니다. 이 배열은 조건을 담고 있습니다. 여기서 조건은 boolean 형태의 표현식이 아닌, 어떤 값의 변경이 일어날 때를 의미합니다. 따라서, 해당 배열엔 어떤 값의 목록이 들어갑니다. 이 배열을 특별히 종속성 배열이라고 부릅니다.
API
- useEffect의 두 번째 인자는 종속성 배열입니다. 배열 내의 종속성1, 또는 종속성2의 값이 변할 때, 첫 번째 인자의 함수가 실행됩니다.
- 배열 내의 어떤 값이 변할 때에만, (effect가 발생하는) 함수가 실행됩니다.
단 한 번만 실행되는 Effect 함수
- 빈 배열 넣기
- 아무것도 넣지 않기 (기본 형태)
- 2번 기본형태의 useEffect는 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트될 때 effect 함수가 실행됨
- 빈 배열을 useEffect의 두 번째 인자로 사용하면, 이때에는 컴포넌트가 처음 생성될 때만 effect 함수가 실행됩니다.
이것이 언제 필요할까요? 대표적으로 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때에 사용할 수 있습니다.
컴포넌트 내에서의 Ajax 요청

AJAX 요청
예시

AJAX 요청이 매우 느릴 경우?

- 모든 네트워크 요청이 항상 즉각적인 응답을 가져다주는 것은 아닙니다. 외부 API 접속이 느릴 경우를 고려하여, 로딩 화면(loading indicator)의 구현은 필수적입니다.
- 기본적으로, Loading indicator의 구현은 어떻게 처리할 수 있을까요? 여기에도 상태 처리가 필요합니다.

- fetch 요청의 전후로 setIsLoading을 설정해 주어 보다 나은 UX를 구현할 수 있습니다.
