ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React Custom Component
    FE 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>
    <input
    type="text"
    required
    value={title}
    onChange={onChangeText}
    placeholder="제목을 입력해주세요."
    />
    <label>내용</label>
    <textarea
    required
    value={body}
    onChange={onChangeBody}
    placeholder="내용을 입력해주세요."
    ></textarea>
    <label>작성자</label>
    <select
    value={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
Designed by Tistory.