어제 토스 slash 2023의 유튜브라이브영상을 보고 버튼을 누르거나 하는 사용자의 행동에 인터렉션을 주는 것이 좋은 UI/UX 라는 것을 보면서 제 포트폴리오 사이트는 이부분이 부족하다는 것을 깨달았습니다.
제 포트폴리오 사이트에서 '포트폴리오 보러가기' 버튼을 클릭했을 때 padding을 더 추가해서 버튼이 더 커지도록 코드를 추가했습니다.
결과적으로 버튼을 눌렀을 때 보여지는 반응이 있으니 더 좋았습니다.
또한, 그 과정에서 기존에 작성했던 ProjectPage 컴포넌트의 코드를 보니 UI 코드와 검색관련 코드가 함께 있어서 코드의 가독성이 좋지 않았습니다.
따라서
import Projects from "components/Projects";
import "./index.css";
import { AiOutlineArrowLeft } from "react-icons/ai";
import Link from "next/link";
import data from "data/projects";
import { useCallback, useReducer } from "react";
import { AiOutlineSearch } from "react-icons/ai";
import { Project } from "types/types";
const ProjectPage = () => {
const reducer = (state: Project[], action: any) => {
switch (action.type) {
case "CHANGE_INPUT":
const filteredData = data.filter(
(project) =>
project.title
.toLowerCase()
.includes(action.payload.toLowerCase()) ||
project.description
.toLowerCase()
.includes(action.payload.toLowerCase()) ||
project.techstack
.toLowerCase()
.includes(action.payload.toLowerCase())
);
return filteredData;
default:
return state;
}
};
const [state, dispatch] = useReducer(reducer, data);
const onSearch = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
dispatch({
type: "CHANGE_INPUT",
payload: event.target.value,
});
}, []);
return (
<div className="background">
<div className="page_container">
<Link href={"/"}>
<AiOutlineArrowLeft size={20} color={"gray"} />
</Link>
<AiOutlineSearch size={17} style={{ marginLeft: "10px" }} />
<input
placeholder="Enter your search term"
onChange={onSearch}
style={{
width: "215px",
padding: "6px",
border: "1px solid #ccc",
borderRadius: "5px",
}}
/>
<Projects data={state} />
</div>
</div>
);
};
export default ProjectPage;
위에 코드에 있는 검색로직인 reducer 함수 등의 코드를 useProjectSearch 라는 이름의 훅으로 분리하고 전체 프로젝트 목록에서 검색한 키워드가 포함된 프로젝트들인 state , onSearch라는 함수를 리턴하도록 했습니다.
import { useReducer, useCallback } from "react";
import { Project } from "types/types";
import data from "data/projects";
type Action = {
type: "CHANGE_INPUT";
payload: string;
};
type State = Project[];
const reducer = (state: State, action: Action) => {
switch (action.type) {
case "CHANGE_INPUT":
const filteredData = data.filter(
(project) =>
project.title
.toLowerCase()
.includes(action.payload.toLowerCase()) ||
project.description
.toLowerCase()
.includes(action.payload.toLowerCase()) ||
project.techstack
.toLowerCase()
.includes(action.payload.toLowerCase())
);
return filteredData;
default:
return state;
}
};
const useProjectSearch = (initialData: Project[]) => {
const [state, dispatch] = useReducer(reducer, initialData);
const onSearch = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
dispatch({
type: "CHANGE_INPUT",
payload: event.target.value,
});
}, []);
return { state, onSearch };
};
export default useProjectSearch;
import Projects from "components/Projects";
import "./index.css";
import { AiOutlineArrowLeft } from "react-icons/ai";
import Link from "next/link";
import { AiOutlineSearch } from "react-icons/ai";
import useProjectSearch from "hooks/useProjectSearch";
import data from "data/projects";
const ProjectPage = () => {
const { state, onSearch } = useProjectSearch(data);
return (
<div className="background">
<div className="page_container">
<Link href={"/"}>
<AiOutlineArrowLeft size={20} color={"gray"} />
</Link>
<AiOutlineSearch size={17} style={{ marginLeft: "10px" }} />
<input
placeholder="Enter your search term"
onChange={onSearch}
style={{
width: "215px",
padding: "6px",
border: "1px solid #ccc",
borderRadius: "5px",
}}
/>
<Projects data={state} />
</div>
</div>
);
};
export default ProjectPage;
'프로젝트' 카테고리의 다른 글
포트폴리오 사이트 React Query 5 버전으로 업데이트 (0) | 2023.10.22 |
---|---|
포트폴리오사이트 UI를 개선하며 (0) | 2023.03.23 |
SEO 개선 with 구글 애널리틱스 (0) | 2023.03.14 |
React-router-dom v6에서는 match대신 useParams (0) | 2022.09.12 |
react 게시판 프로젝트 회고록 (0) | 2022.09.10 |
댓글