React 데이터 흐름

시디·2022년 1월 30일
0

웹개발

목록 보기
7/9

React에서의 데이터 흐름

React 개발 방식의 가장 큰 특징은 컴포넌트 단위로 개발한다는 것이다. 앱의 프로토타입을 전달받은 경우 먼저 컴포넌트를 찾아야 한다. 컴포넌트를 만든 후 페이지를 조립해 나간다. → 상향식(bottom-up) 개발

⇒ 테스트가 쉽고 확장성이 좋다!

✅ 앱의 디자인을 전달받으면 컴포넌트 계층 구조로 나누는 것이 최우선!

React에서 데이터는 위에서 아래로 흐른다(Flux 패턴 ). 컴포넌트는 부모 컴포넌트로부터 props를 전달받을 수 있다. 즉 데이터의 흐름은 하향식(top-down)이다.

✅ React는 단방향 데이터 흐름(One-way data flow)을 따른다!

상태(state)의 조건

  • 부모로 부터 전달되는 데이터(props)가 아니다.
  • 변할 수 있는 데이터이다.
  • 컴포넌트 안의 다른 state나 props로 계산이 가능하지 않다.

상태(state) 위치 정하기

상태가 특정 컴포넌트에만 유의미하다면 특정 컴포넌트에 위치하면 되지만, 하나의 상태에 여러 컴포넌트가 영향을 받는 경우 공통 부모 컴포넌트에 위시치켜야 한다.

역방향 데이터 흐름

부모 컴포넌트의 상태가 하위 컴포넌트에 의해 변하는 것

⇒ State 끌어 올리기(Lifting state up) : handler를 하위 컴포넌트에 props로 전달

Lifting State Up

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

Effect Hook

Side Effect(부수 효과) : ****함수 내에서 어떤 구현이 함수 외부에 영향을 끼는 경우 해당 함수는 Side Effect가 있다.

React는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.

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

새롭게 컴포넌트가 렌더링될 때 Effect Hook이 실행

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

ex) 브라우저 API를 이용해 타이틀 변경

import { useEffect, useState } from "react";
import "./styles.css";

export default function App() {
  const proverbs = [
    "좌절감으로 배움을 늦추지 마라",
    "Stay hungry, Stay foolish",
    "Memento Mori",
    "Carpe diem",
    "배움에는 끝이 없다"
  ];
  const [idx, setIdx] = useState(0);

  const handleClick = () => {
    setIdx(idx === proverbs.length - 1 ? 0 : idx + 1);
  };

  return (
    <div className="App">
      <button onClick={handleClick}>명언 제조</button>
      <Proverb saying={proverbs[idx]} />
    </div>
  );
}

function Proverb({ saying }) {
  useEffect(() => {
    document.title = saying;
  });
  return (
    <div>
      <h3>오늘의 명언</h3>
      <div>{saying}</div>
    </div>
  );
}

조건부 effect(dependency array)

useEffect의 두번째 인자는 배열로 조건을 담고 있다. 조건은 어떤 값의 변경이 일어 날 때를 의미한다. 배열에는 어떤 값이 들어간다. 이 배열을 종속성 배열이라고 부른다.

종속성 배열내의 종속성의 값이 변할 때 첫번째 인자의 함수가 실행된다.

import { useEffect, useState } from "react";
import "./styles.css";
import { getProverbs } from "./storageUtil";

export default function App() {
  const [proverbs, setProverbs] = useState([]);
  const [filter, setFilter] = useState("");
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("언제 effect 함수가 불릴까요?");
    const result = getProverbs(filter);
    setProverbs(result);
  }, [filter,count]);

  const handleChange = (e) => {
    setFilter(e.target.value);
  };

  const handleCounterClick = () => {
    setCount(count + 1);
  };

  return (
    <div className="App">
      필터
      <input type="text" value={filter} onChange={handleChange} />
      <ul>
        {proverbs.map((prvb, i) => (
          <Proverb saying={prvb} key={i} />
        ))}
      </ul>
      <button onClick={handleCounterClick}>카운터 값: {count}</button>
    </div>
  );
}

function Proverb({ saying }) {
  return <li>{saying}</li>;
}

✅ 두번째 인자로 빈 배열을 넣는 경우 컴포넌트가 처음 생성될 때만 effect함수가 실행된다.

⇒ 외부 API를 통해 리소스를 받아오고 더이상 API호출이 필요하지 않을 경우 사용

fetch API 사용한 AJAX 요청

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

✅ 외부 API 접속이 느릴 경우를 고려하여, 로딩 화면(loading indicator)의 구현(fetch 요청의 전후로 setIsLoading을 설정해주어 보다 나은 UX를 구현)

profile
콰삭칩을 그리워하는 개발자 입니다.

0개의 댓글