-
React Custom ComponentFE 2023. 7. 20. 18:02
App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';import Home from './Home';import Navbar from './component/Navbar';import CreateBlog from './blogComponent/CreateBlog';import BlogDetails from './blogComponent/BlogDetail';import NotFound from './component/NotFound';import Footer from './component/Footer';import { useEffect, useState, Suspense, lazy } from 'react';
/* react.lazy()와 suspense를 사용해 App 컴포넌트를 리팩토링 해보세요. */
function App() {const [blogs, setBlogs] = useState(null);const [isPending, setIsPending] = useState(true);const [error, setError] = useState(null);
/* get 메소드를 통해 데이터를 받아오는 useEffect hook은 컴포넌트 내 여기저기 존재하고 있습니다. *//* 해당 hook은 반복이 되는 부분이 있으므로 어떻게 custom hook으로 만들 수 있을지 고민해 봅시다. *//* util 폴더 내에 존재하는 useFetch에 custom hook을 작성해 주세요. */useEffect(() => {setTimeout(() => {fetch('http://localhost:3001/blogs').then(res => {if (!res.ok) {throw Error('could not fetch the data for that resource');}return res.json();}).then(data => {setIsPending(false);setBlogs(data);setError(null);}).catch(err => {setIsPending(false);setError(err.message);})}, 1000);}, [])
const Home = lazy(() => import ('./Home'));const CreateBlog = lazy(() => import ('./blogComponent/CreateBlog'));const BlogDetails = lazy(() => import ('./blogComponent/BlogDetail'));const NotFound = lazy(() => import ('./component/NotFound'));
return (<BrowserRouter>{ error && <div>{ error }</div> }<div className="app"><Navbar /><div className="content"><Suspense fallback={<div>Loading...</div>}><Routes><Route exact path="/" element={<Home blogs={blogs} isPending={isPending} />} /><Route path="/create" element={<CreateBlog />} /><Route path="/blogs/:id" element={<BlogDetails />} /><Route path="/blogs/:id" element={<NotFound />} /></Routes></Suspense></div><Footer/></div></BrowserRouter>);}
export default App;react.lazy()와 suspense를 사용하여 리팩토링함. Route 설정한 컴포넌트를 lazy로 바꾸고 Susptense로 감쌌다.
BlogDetail.js
import { useEffect, useState } from "react";import{ useNavigate, useParams } from "react-router-dom";
const BlogDetails = () => {const [blog, setBlogs] = useState(null);const [isPending, setIsPending] = useState(true);const [error, setError] = useState(null);const [isLike, setIsLike] = useState(false);
const { id } = useParams();const navigate = useNavigate();/* 현재는 개별 블로그 내용으로 진입해도 내용이 보이지 않습니다. *//* useParams와 id를 이용하여 개별 블로그의 내용이 보일 수 있게 해봅시다. */useEffect(() => {setTimeout(() => {fetch(`http://localhost:3001/blogs/${id}`).then(res => {if (!res.ok) {throw Error('could not fetch the data for that resource');}return res.json();}).then(data => {setIsPending(false);setBlogs(data);setError(null);}).catch(err => {setIsPending(false);setError(err.message);})}, 1000);}, [])
const handleDeleteClick = () => {/* delete 버튼을 누르면 다시 home으로 리다이렉트 되어야 합니다. *//* useNavigate()를 이용하여 handleDeleteClick 로직을 작성해주세요. */navigate('/');console.log('delete!');}
const handleLikeClick = () => {/* 하트를 누르면 home에서 새로고침을 했을 때 숫자가 올라가야 합니다. *//* isLike와 blog.likes를 이용하여 handleLikeClick의 로직을 작성해주세요. */fetch(`http://localhost:3001/blogs/${id}`) {method: "PUT",headers: {"Content-Type": "appLication/json",},body: JSON.stringify({...blog,likes: blog.likes + 1,isLike: true,}),}.then((res) => res.json()).then((data) => {setBlog(data);setIsLike(true);});};
return (<div className="blog-details">{ isPending && <div>Loading...</div> }{ error && <div>{ error }</div> }{ blog && (<article><h2>{ blog[id-1].title }</h2><p>Written by { blog[id-1].author }</p><div>{ blog[id-1].body }</div><button onClick={handleLikeClick}>{/* isLike에 의해 조건부 렌더링으로 빨간 하트(❤️)와 하얀 하트(🤍)가 번갈아 보여야 합니다. */}{isLike ? '❤️' : '🤍'}</button><button onClick={handleDeleteClick}>delete</button><button onClick={conutLike}></button></article>)}</div>);}
export default BlogDetails;PUT으로 요청하고 id 값을 받아왔다.
CreateBlog.js
import { useState } from "react";import { useNavigate } from "react-router-dom";import useInput from "../util/useInput";
const CreateBlog = () => {const [title, setTitle] = useState('');const [body, setBody] = useState('');const [author, setAuthor] = useState('김코딩');const navigate = useNavigate();
const handleSubmit = (e) => {e.preventDefault();/* 등록 버튼을 누르면 게시물이 등록이 되며 home으로 리다이렉트 되어야 합니다. *//* 작성한 내용과 useNavigate를 이용하여 handleSubmit의 로직을 작성해보세요. */console.log(e.type);const data = { title, body, author, likes: 0 }fetch('http://localhost:3001/blogs/', {method: "POST",headers: { "Content-type": "Application/json" },body: JSON.stringify(data)}).then(res => {if (!res.ok) {throw Error('could not fetch the data for that resource', {method: "DELETE"});}return res.json();}).then(() => {navigate('/')window.location.reload();}).catch(err => {console.error("Error", err);})}
return (<div className="create"><h2>Add a New Blog</h2><form onSubmit={handleSubmit}><label>제목</label><inputtype="text"requiredvalue={title}onChange={onChangeText}placeholder="제목을 입력해주세요."/><label>내용</label><textarearequiredvalue={body}onChange={onChangeBody}placeholder="내용을 입력해주세요."></textarea><label>작성자</label><selectvalue={author}onChange={onChangeAuthor}><option value="kimcoding">김코딩</option><option value="parkhacker">박해커</option></select><button>등록</button></form></div>);}export default CreateBlog;UseFetch, UseInput 컴포넌트는 이해가 안 가서 이해한 후에 다시 해봐야 할 것 같다
'FE' 카테고리의 다른 글
[TypeScript] 기초1 (0) 2023.07.26 Component Library (0) 2023.07.23 [React] 심화 (0) 2023.07.19 [React] 심화 (0) 2023.07.18 [솔로 프로젝트] (0) 2023.07.17