[React] 컴포넌트 내 Ajax 요청

tnsdlznf23·2023년 3월 26일
0

컴포넌트 내에 필터링하는 법

<데이터 파일>

localStorage.setItem(
  "proverbs", //키값
  JSON.stringify([
    "좌절감으로 배움을 늦추지 마라",
    "Stay hungry, Stay foolish",
    "Memento Mori",
    "Carpe diem",
    "배움에는 끝이 없다"
  ])
);

export function getProverbs(filterBy = "") {
  const json = localStorage.getItem("proverbs"); //proverbs키에 대한 값을 가져옴
  const proverbs = JSON.parse(json) || []; // 키값 JSON 형태로 가져옴,만약 값이 없다면 빈배열 가져옴
  return proverbs.filter((prvb) =>
    prvb.toLowerCase().includes(filterBy.toLowerCase())
  ); //필터링 된 배열 반환
}

1. 컴포넌트 내에서 필터링
처음 단 한번, 외부 API로부터 목록을 받아오고 filter 함수를 이용한다.

import { useEffect, useState } from "react";
import "./styles.css";
import { getProverbs } from "./storageUtil"; //필터링 함수 가져오기

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

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

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

  return (
    <div className="App">
      필터
      <input type="text" value={filter} onChange={handleChange} />
      <ul>
        {proverbs
          .filter((prvb) => {
            return prvb.toLowerCase().includes(filter.toLowerCase());
          })
          .map((prvb, i) => (
            <Proverb saying={prvb} key={i} />
          ))}
      </ul>
    </div>
  );
}

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

2. 컴포넌트 외부에서 필터링
검색어가 바뀔 때마다, 외부 API를 호출한다 (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]); //검색어 바뀔때마다 외부 API 호출

  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>;
}

두 방식의 차이점
1. 컴포넌트 내부에서 처리: HTTP 요청의 빈도를 줄일 수 있으나 브라우저의 메모리 상에 많은 데이터를 가지게 되므로 클라이언트의 부담이 늘어난다.
2. 컴포넌트 외부에서 처리(useEffect): 브라우저가 필터링 구현을 생각하지 않아도 되나 빈번한 HTTP 요청이 일어나게 되며 서버가 필터링을 처리하므로 서버가 부담을 가져간다.

AJAX 요청

fetch API를 써서 서버에 요청할 때 명언을 제공하는 API의 엔드포인트가 http://서버주소/proverbs라고 가정하면 아래와 같이 코드를 작성할 수 있다.

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

AJAX 요청이 느릴경우

아래와 같이 로딩 화면을 구현할 수 있다.

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

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

useEffect(() => {
  setIsLoading(true);
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp => resp.json())
    .then(result => {
      setProverbs(result);
      setIsLoading(false);
    });
}, [filter]);
profile
프론트엔드 개발 기록장

0개의 댓글