[TIL : 23] 데이터 흐름의 이해, 비동기 요청 처리

jabae·2021년 11월 16일
0

TIL

목록 보기
23/44

Achievement Goals : React 데이터 흐름

  • React에서의 데이터 흐름, 단방향 데이터 흐름을 이해할 수 있다.

    리액트의 특징 중 하나는 데이터는 위에서 아래로 하향식(top-down) 흐름을 갖는다는 것이다. 데이터를 전달하는 주체는 부모컴포넌트이고, 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못한다. 이러한 단방향 데이터 흐름(one-way data flow) 키워드는 React를 대표하는 설명이 되기도 하며 중요하다.

  • 어떤 컴포넌트에 state가 위치해야 하는지 알 수 있다.

    yes! 🙌
    어떤 state가 두 컴포넌트에 영향을 준다면, 공통 소유 컴포넌트(공통 부모!)를 찾아 그 곳에 상태를 위치치켜준다.

    state는 언제 쓰지?

    • 부모로부터 props를 통해 전달되나? 🙅‍♀️
    • 시간이 지나도 변하지 않나? 🙅‍♀️
    • 컴포넌트 안의 다른 stateprops를 가지고 계산이 가능한가? 🙅‍♀️

    위 경우가 아닐 때 사용한다.👌

  • State 끌어올리기의 개념을 이해할 수 있다.

    단방향 데이터 흐름 원칙에 따르면, 자식 컴포넌트는 부모컴포넌트를 바꿀 수 없다. 하지만 자식컴포넌트에서 버튼을 클릭하고, 이 버튼클릭으로 부모 컴포넌트의 상태를 바꾸고 싶다면? 이러한 문제를 부모 컴포넌트의 상태변경함수를 하위로 전달해서 실행시키는 방법(이것은 마치 콜백함수!),State 끌어올리기(Lifting state up)로 해결할 수 있다.

    그냥 뭉뚱그려 같이 쓰면 안되나? 라고 생각할 수도 있겠지만, 리액트는 컴포넌트 단위로 시작해 페이지를 조립해 나가는 상향식으로 앱을 만들고, 이 컴포넌트는 각각 단일 책임 원칙으로 하나의 일만 하도록 되어있다. 그렇게 해야 테스트가 쉽고 확장성, 유지 보수하기가 좋기 때문이다. 이렇게 컴포넌트 단위로 쪼개기 때문에 위와 같은 일이 빈번히 발생할 수 있다.

  • 상태 변경 함수가 정의된 컴포넌트와, 상태 변경 함수를 호출하는 컴포넌트가 다름을 알 수 있다.

    yes! 👍 위의 예시를 만들어볼까?

    import React, { useState } from "react";
    
    export default function ParentComponent() {
      const [value, setValue] = useState("초깃값을 바꿔봅시다.");
    
      const handleChangeValue = (newValue) => {                        // 상태변경함수
        setValue(newValue);
      };
    
      return (
        <div>
          <div>현재 값은 {value} 입니다.</div>
          <ChildComponent handleButtonClick = {handleChangeValue}/>   // 상태변경함수 전달
        </div>
      );
    }

    우선 위와 같이 부모 컴포넌트에서 state를 위치시키고, 상태변경함수 handleChangeValue를 만들어준다. 그리고 리턴에서, handleButtonClick으로 이 상태변경함수를 전달해 준다.

    function ChildComponent({handleButtonClick}) {
      const handleClick = () => {
        handleButtonClick("자식 컴포넌트에서 값을 바꿨습니다!")
      };
    
      return <button onClick={handleClick}>값 변경</button>;
    }

    그리고 자식 컴포넌트에서 위 상태변경함수props로 받아 클릭이벤트가 발생하면 이 함수를 콜백해 값을 인자로 넣어 실행시킬 수 있다.

Achievement Goals : Effect Hook

  • Side effect가 어떤 의미인지 알 수 있다.

    함수 내의 구현이 외부에 영향을 끼치는 경우를 말한다.

    React 컴포넌트에서 Side Effect

    • 타이머 사용하기 : setTimeout
    • 데이터 가져오기 : fetch API, localStorage
  • Effect Hook을 이용해 비동기 호출 및 AJAX 요청과 같은 side effect를 React 컴포넌트 내에서 처리할 수 있다.

    yes! 👏
    비동기 요청의 대표적인 예로 맨 아래의 fetch를 처리할 수 있다.

  • Effect Hook에서의 dependency array 사용법을 이해할 수 있다.

    useEffect(함수, [조건1, 조건2, ...]) : useEffect의 첫번째 인자는 실행할 함수, 두번째 인자는 종속성 배열(dependency array)이다. 종속성 배열은 조건으로 넣은 값의 변경이 일어나야 함수를 실행한다는 조건인데, 이 조건들의 목록을 담고 있다. 쉽게 말해 이 조건값이 바뀌어야 함수가 실행된다는 것이다. (여러 state를 넣을 수 있다.)

    • useEffect(함수) : 기본형태로, 조건이 없는 useEffect는 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트될 때 함수가 실행된다.
    • useEffect(함수, []) : 빈배열을 조건으로 갖는 경우, 컴포넌트가 처음 생성될때만 effect 함수가 실행된다. (예. 처음 딱 한 번, 외부 API로 리소스를 받아온 뒤 이후로 API 호출이 필요하지 않을 때)

    처음 조금 어리둥절 할 수 있는데, 상태가 하나만 있다면 조건을 걸지 않아도 된다. 하지만 만약 상태가 하나 이상이라면? 조건값을 걸어주지 않으면 모든 상태가 바뀔 때마다 이 useEffect 함수가 돌아갈 것이다. (이건 너무 불필요하다!)

    export default function App() {
      const [text, setText] = useState("")
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        console.log("언제 effect 함수가 불릴까?");
      }, [count]);
    
    return (
        <div>
          <label>text: </label>
          <input onChange={(e) => setText(e.target.value)} value={text}></input>
          <button onClick={() => setCount(count + 1)}>카운터 값: {count}</button>
        </div>
      );
    }

    만약 위의 useEffect에서 조건 [count]를 걸어주지 않는다면, inputtext 내용이 바뀔 때에도, button이 눌릴 때에도 모두 effect 함수가 돌아가 콘솔에 계속 찍힐 것이다. 하지만 [count]를 조건으로 걸어준다면, 오직 count의 상태가 바뀔 때에만 실행되는 것을 볼 수 있다.

  • 컴포넌트 내에서 네트워크 요청시, 로딩 화면과 같이 보다 나은 UI를 만드는 법을 이해할 수 있다.

    네트워크 요청과 데이터 처리 과정이 길 경우, 로딩화면은 필수적이다!
    (그냥 빈 화면을 덩그러니 쳐다보고 있는 자신을 생각해 보자. 너무 답답해 🤦‍♀️)

    const [isLoading, setIsLoading] = useState(false)
    
    // 생략...
    return {isLoading ? <로딩화면 컴포넌트 /> : <div>로딩 완료 화면</div>}

    이렇게 위와 같이 상태에 따라 로딩화면을 보여줄 지, 완료된 화면을 보여줄 지 만들어줄 수 있다.

    useEffect(() => {
      setIsLoading(true);        // 로딩화면을 렌더링하고,
      fetch(url)
        .then(response => response.json())
        .then(result => {
          상태변경함수(result);      // 서버에서 데이터를 요청하고 받아오면 상태를 변경시킨다
          setIsLoading(false);   // 이후 로딩 완료 화면을 렌더링하도록 로딩상태를 변경시킨다
        });
    }, [url]);                   // 조건에 url을 넣어 url이 바뀔 때마다 실행한다

    혹은 이렇게 시간이 오래 걸릴 수 있는 fetch 요청 전후로 로딩화면 상태를 변화시켜 주면서 더 나은 사용자 경험을 줄 수도 있다.

profile
it's me!:)

0개의 댓글