이번 포스트에서는 검색 기능 구현과 관련된 내용을 다루고, json-server
라이브러리의 버전 변경에 대해 알아보았습니다. 교안을 바탕으로 코드의 주요 변경사항과 그에 대한 설명을 포함하여 오늘 배운 내용을 정리해보겠습니다.
json-server
버전 변경 🔄json-server
라이브러리의 버전을 0.17.4
로 변경하여 호환성 문제를 해결했습니다.
npm uninstall json-server
npm install json-server@0.17.4
코드 설명:
json-server
를 제거한 후, 특정 버전인 0.17.4
로 재설치합니다.추가 설명:
라이브러리의 버전을 명시적으로 지정함으로써 예기치 않은 버전 업데이트로 인한 호환성 문제를 예방할 수 있습니다. 이는 안정적인 개발 환경을 유지하는 데 중요한 역할을 합니다.
src/api/canvas.js
수정 📄getCanvases
함수의 구현을 변경하여 검색 기능을 강화했습니다.
import { canvases } from './http';
**export function getCanvases(params) {
return canvases.get('/', { params });
}**
코드 설명:
getCanvases
함수는 전달된 params
를 사용하여 캔버스 데이터를 가져옵니다.추가 설명:
검색 기능을 구현하기 위해 params
를 통해 제목에 특정 키워드가 포함된 데이터를 필터링할 수 있도록 했습니다. 이를 통해 사용자가 원하는 캔버스를 보다 쉽게 찾을 수 있습니다.
src/pages/Home.jsx
수정 🏠Home 컴포넌트에 검색 기능을 추가하고, 관련 상태 관리를 구현했습니다.
import ViewToggle from '../components/ViewToggle';
import { getCanvases } from '../api/canvas';
function Home() {
**+ const [searchText, setSearchText] = useState();**
const [isGridView, setIsGridView] = useState(true);
const [data, setData] = useState([]);
**+ async function fetchData(params) {
+ const response = await getCanvases(params);**
setData(response.data);
}
useEffect(() => {
**+ fetchData({ title_like: searchText });
+ }, [searchText]);**
const handleDeleteItem = id => {
setData(data.filter(item => item.id !== id));
};
return (
<div className="container mx-auto px-4 py-16">
<div className="mb-6 flex flex-col sm:flex-row items-center justify-between">
... 생략 ...
<ViewToggle isGridView={isGridView} setIsGridView={setIsGridView} />
</div>
<CanvasList
**+ filteredData={data}**
isGridView={isGridView}
searchText={searchText}
onDeleteItem={handleDeleteItem}
... 생략 ...
)
}
코드 설명:
searchText
상태를 추가하여 사용자의 검색어를 관리합니다.fetchData
함수를 통해 검색어에 맞는 데이터를 불러옵니다.useEffect
훅을 사용하여 searchText
가 변경될 때마다 데이터를 다시 가져옵니다.CanvasList
컴포넌트에 filteredData
를 전달하여 필터링된 데이터를 표시합니다.추가 설명:
검색 기능을 통해 사용자가 원하는 캔버스를 빠르게 찾을 수 있게 되었습니다. 상태 관리를 통해 검색어 입력 시 자동으로 데이터가 갱신되도록 구현하여 사용자 경험을 향상시켰습니다.
json-server
라이브러리의 버전 변경을 통해 호환성 문제를 해결하는 방법과, 검색 기능을 구현하여 사용자 경험을 향상시키는 방법에 대해 배웠습니다. 특히, getCanvases
함수의 파라미터 활용과 Home
컴포넌트에서의 상태 관리 방식을 통해 효율적인 데이터 필터링을 구현할 수 있었습니다. 이러한 내용을 통해 프론트엔드 개발 시 라이브러리 관리와 사용자 친화적인 기능 구현의 중요성을 다시 한번 확인할 수 있었습니다.
이번 포스트에서는 검색 기능 구현과 라이브러리 버전 변경에 대해 다루었습니다. 교안을 바탕으로 코드의 주요 변경사항과 그에 대한 설명을 포함하여 내용을 정리해보겠습니다.
json-server
버전 변경 🔄json-server
라이브러리의 버전을 0.17.4
로 변경하여 호환성 문제를 해결했습니다.
npm uninstall json-server
npm install json-server@0.17.4
코드 설명:
json-server
를 제거한 후, 특정 버전인 0.17.4
로 재설치합니다.추가 설명:
라이브러리의 버전을 명시적으로 지정함으로써 예기치 않은 버전 업데이트로 인한 호환성 문제를 예방할 수 있습니다. 이는 안정적인 개발 환경을 유지하는 데 중요한 역할을 합니다.
src/api/canvas.js
수정 📄getCanvases
함수의 구현을 변경하여 검색 기능을 강화했습니다.
import { canvases } from './http';
**export function getCanvases(params) {
return canvases.get('/', { params });
}**
코드 설명:
getCanvases
함수는 전달된 params
를 사용하여 캔버스 데이터를 가져옵니다.추가 설명:
검색 기능을 구현하기 위해 params
를 통해 제목에 특정 키워드가 포함된 데이터를 필터링할 수 있도록 했습니다. 이를 통해 사용자가 원하는 캔버스를 보다 쉽게 찾을 수 있습니다.
src/pages/Home.jsx
수정 🏠Home 컴포넌트에 검색 기능을 추가하고, 관련 상태 관리를 구현했습니다.
import { useEffect, useState } from 'react';
+import { getCanvases } from '../api/canvas';
import CanvasList from '../components/CanvasList';
import SearchBar from '../components/SearchBar';
import ViewToggle from '../components/ViewToggle';
+import Loading from '../components/Loading';
+import Error from '../components/Error';
function Home() {
const [searchText, setSearchText] = useState();
const [isGridView, setIsGridView] = useState(true);
const [data, setData] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
async function fetchData(params) {
+ try {
+ setIsLoading(true);
+ setError(null);
+ await new Promise(resolver => setTimeout(resolver, 2000));
+ const response = await getCanvases(params);
+ setData(response.data);
+ } catch (err) {
+ setError(err);
+ } finally {
+ setIsLoading(false);
+ }
}
useEffect(() => {
// ... 생략 ...
<SearchBar searchText={searchText} setSearchText={setSearchText} />
<ViewToggle isGridView={isGridView} setIsGridView={setIsGridView} />
</div>
+ {isLoading && <Loading />}
+ {error && (
+ <Error
+ message={error.message}
+ onRetry={() => fetchData({ title_like: searchText })}
+ />
+ )}
+ {!isLoading && !error && (
+ <CanvasList
+ filteredData={data}
+ isGridView={isGridView}
+ searchText={searchText}
+ onDeleteItem={handleDeleteItem}
+ />
+ )}
</div>
);
}
코드 설명:
searchText
, isLoading
, error
등의 상태를 추가하여 검색어 입력, 로딩 상태, 오류 상태를 관리합니다.fetchData
함수에서 데이터를 가져올 때 로딩 상태를 설정하고, 오류 발생 시 오류 상태를 업데이트합니다.useEffect
훅을 사용하여 searchText
가 변경될 때마다 fetchData
를 호출하여 데이터를 다시 가져옵니다.Loading
컴포넌트를, 오류 발생 시 Error
컴포넌트를, 정상적으로 데이터를 가져왔을 때는 CanvasList
컴포넌트를 표시합니다.추가 설명:
로딩과 오류 상태를 관리함으로써 사용자에게 현재 데이터 요청 상태를 명확히 전달할 수 있게 되었습니다. Loading
컴포넌트를 통해 데이터 로딩 중임을 시각적으로 표시하고, Error
컴포넌트를 통해 오류 발생 시 재시도할 수 있는 기능을 제공합니다. 이는 사용자 경험을 향상시키는 중요한 개선 사항입니다.
Loading
과 Error
UI 컴포넌트를 추가하여 사용자에게 데이터 요청 상태를 명확히 전달합니다.
src/components/Loading.jsx
import { AiOutlineLoading3Quarters } from 'react-icons/ai';
function Loading() {
return (
<div className="flex items-center justify-center ">
<div className="text-center">
<AiOutlineLoading3Quarters className="animate-spin text-6xl text-blue-500 mx-auto mb-4" />
<p className="text-xl font-semibold text-gray-700">Loading data...</p>
</div>
</div>
);
}
export default Loading;
코드 설명:
AiOutlineLoading3Quarters
아이콘을 사용하여 로딩 스피너를 표시합니다.src/components/Error.jsx
function Error({ message, onRetry }) {
return (
<div className="flex items-center justify-center">
<div className="text-center p-8">
<p className="text-xl font-semibold text-red-600 mb-4">{message}</p>
<button
onClick={onRetry}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition duration-300 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
>
재시도
</button>
</div>
</div>
);
}
export default Error;
코드 설명:
onRetry
함수를 호출하여 데이터를 다시 요청할 수 있습니다.SearchBar
컴포넌트에서 searchText
의 기본값을 할당하여 초기 렌더링 시 발생할 수 있는 오류를 방지했습니다.
import { FaSearch } from 'react-icons/fa';
+function SearchBar({ searchText = '', setSearchText }) {
return (
<div className="relative w-full sm:w-64 mb-4 sm:mb-0">
<input
// ...생략...
코드 설명:
searchText
의 기본값을 빈 문자열로 설정하여, 값이 undefined
일 경우에도 정상적으로 동작하도록 합니다.Home
컴포넌트에서 React Fragment를 사용하여 불필요한 DOM 요소 생성을 방지했습니다.
function Home() {
// ...생략...
return (
+ <>
<div className="mb-6 flex flex-col sm:flex-row items-center justify-between">
<SearchBar searchText={searchText} setSearchText={setSearchText} />
<ViewToggle isGridView={isGridView} setIsGridView={setIsGridView} />
</div>
+ {isLoading && <Loading />}
+ {error && (
+ <Error
+ message={error.message}
+ onRetry={() => fetchData({ title_like: searchText })}
+ />
+ )}
+ {!isLoading && !error && (
+ <CanvasList
+ filteredData={data}
+ isGridView={isGridView}
+ searchText={searchText}
+ onDeleteItem={handleDeleteItem}
+ />
+ )}
</>
);
}
코드 설명:
<> </>
)를 사용하여 여러 요소를 그룹화하면서 불필요한 래퍼 DOM 요소 생성을 방지합니다.이번 실습을 통해 로딩 및 오류 상태 관리를 추가하여 사용자 경험을 향상시키는 방법을 배웠습니다. Loading
컴포넌트를 통해 데이터 요청 중임을 시각적으로 표시하고, Error
컴포넌트를 통해 오류 발생 시 재시도 기능을 제공함으로써 보다 안정적인 애플리케이션을 구현할 수 있게 되었습니다. 또한, SearchBar
의 기본값 할당과 React Fragment 사용을 통해 코드의 안정성과 효율성을 높일 수 있었습니다.
강의를 들으며 등록구현
, 공통 컴포넌트
, 그리고 dayjs
라이브러리에 대해 배웠습니다. 이번 포스트에서는 교안을 바탕으로 배운 내용을 정리하고, 코드의 주요 변경사항과 그에 대한 설명을 포함하여 오늘 배운 내용을 되새겨보겠습니다.
src/api/canvas.js
파일에서 캔버스 데이터를 등록하고 조회하는 기능을 구현했습니다. 주요 변경사항은 uuid
와 dayjs
라이브러리를 도입하여 새로운 캔버스를 생성할 때 고유한 ID와 현재 시간을 추가하는 것입니다.
import { canvases } from './http';
**+import { v4 as uuidv4 } from 'uuid';
+import dayjs from 'dayjs';**
export function getCanvases(params) {
**+ const payload = Object.assign(
+ {
+ _sort: 'lastModified',
+ _order: 'desc',
+ },
+ params,
+ );
+ return canvases.get('/', { params: payload });
+}
+
+export function createCanvas() {
+ const newCanvas = {
+ title: uuidv4().substring(0, 4) + '_새로운 린 캔버스',
+ lastModified: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ category: '신규',
+ };
+ return canvases.post('/', newCanvas);**
}
코드 설명:
uuidv4
를 사용하여 새로운 캔버스의 고유한 ID를 생성하고, 이를 제목에 일부 포함시켰습니다.dayjs
를 활용하여 현재 시간을 lastModified
필드에 포맷팅하여 저장합니다.getCanvases
함수에서는 요청 시 정렬 옵션을 추가하여 최근에 수정된 캔버스가 먼저 조회되도록 했습니다.추가 설명:
이러한 변경을 통해 캔버스의 생성과 조회 시 더 체계적인 데이터 관리가 가능해졌습니다. 특히, dayjs
를 사용함으로써 시간 관련 처리가 간편해졌습니다.
공통으로 사용할 버튼 컴포넌트를 src/components/Button.jsx
에 구현했습니다. 이 컴포넌트는 로딩 상태를 관리하며, onClick
이벤트 핸들링 시 유효성 체크를 추가하여 에러를 방지합니다.
import { FaSpinner } from 'react-icons/fa';
function Button({ loading = false, onClick, className, children }) {
const clazz = [
'bg-blue-500 hover:bg-blue-600 text-white font-bold py-1.5 px-4 rounded transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50',
className,
].join(' ');
const handleClick = () => {
**// onClick이 undefined 일 경우 아래 로직을 수행하지 않으면 에러를 방지할 수 있어요!**
if (!onClick) {
return;
}
if (loading) {
return;
}
onClick();
};
return (
<button className={clazz} onClick={handleClick} disabled={loading}>
<span className="flex items-center justify-center">
{loading && <FaSpinner className="animate-spin mr-2" />}
{children}
</span>
</button>
);
}
export default Button;
코드 설명:
onClick
이 정의되지 않은 경우를 체크하여 에러를 방지합니다.추가 설명:
이 공통 버튼 컴포넌트를 사용하면 여러 곳에서 일관된 스타일과 기능을 유지할 수 있으며, 로딩 상태 관리가 용이해졌습니다.
src/pages/Home.jsx
파일에서 공통 버튼 컴포넌트를 활용하여 캔버스 등록 기능을 추가했습니다. 또한, createCanvas
와 getCanvases
함수를 불러와 데이터를 관리합니다.
import { useEffect, useState } from 'react';
+import { createCanvas, getCanvases } from '../api/canvas';
import CanvasList from '../components/CanvasList';
import SearchBar from '../components/SearchBar';
import ViewToggle from '../components/ViewToggle';
import Loading from '../components/Loading';
import Error from '../components/Error';
+import Button from '../components/Button';
function Home() {
const [searchText, setSearchText] = useState();
const [isGridView, setIsGridView] = useState(true);
// ...생략...
try {
setIsLoading(true);
setError(null);
+ await new Promise(resolver => setTimeout(resolver, 1000));
const response = await getCanvases(params);
setData(response.data);
} catch (err) {
// ...생략...
setData(data.filter(item => item.id !== id));
};
const [isLoadingCreate, setIsLoadingCreate] = useState(false);
const handleCreateCanvas = async () => {
try {
setIsLoadingCreate(true);
await new Promise(resolver => setTimeout(resolver, 1000));
await createCanvas();
fetchData({ title_like: searchText });
} catch (err) {
alert(err.message);
} finally {
setIsLoadingCreate(false);
}
};
return (
<>
<div className="mb-6 flex flex-col sm:flex-row items-center justify-between">
<SearchBar searchText={searchText} setSearchText={setSearchText} />
<ViewToggle isGridView={isGridView} setIsGridView={setIsGridView} />
</div>
<div className="flex justify-end mb-6">
<Button onClick={handleCreateCanvas} loading={isLoadingCreate}>
등록하기
</Button>
</div>
{isLoading && <Loading />}
{error && (
<Error
// ...생략...
)
}
코드 설명:
createCanvas
와 getCanvases
함수를 불러와 데이터를 관리합니다.Button
컴포넌트를 사용하여 캔버스 등록 버튼을 구현했습니다. 버튼 클릭 시 handleCreateCanvas
함수가 호출되며, 로딩 상태를 관리합니다.추가 설명:
공통 버튼 컴포넌트를 활용함으로써 버튼의 일관된 스타일과 로딩 상태 관리가 가능해졌습니다. 또한, 데이터 관리 로직이 더욱 명확해졌습니다.
dayjs
라이브러리를 활용하여 날짜와 시간을 효과적으로 관리하는 방법과, 공통 컴포넌트를 만들어 코드의 재사용성을 높이는 방법에 대해 배웠습니다. 또한, 캔버스 등록 및 조회 기능을 구현하며 프론트엔드 개발의 기본적인 데이터 관리 흐름을 이해할 수 있었습니다. 이러한 내용을 통해 더욱 효율적이고 유지보수가 쉬운 코드를 작성할 수 있게 되었습니다.