<데이터 파일>
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 요청이 일어나게 되며 서버가 필터링을 처리하므로 서버가 부담을 가져간다.
fetch API를 써서 서버에 요청할 때 명언을 제공하는 API의 엔드포인트가 http://서버주소/proverbs
라고 가정하면 아래와 같이 코드를 작성할 수 있다.
useEffect(() => { fetch(`http://서버주소/proverbs?q=${filter}`) .then(resp => resp.json()) .then(result => { setProverbs(result); }); }, [filter]);
아래와 같이 로딩 화면을 구현할 수 있다.
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]);