React Custom Hook 사용해보기

쫀구·2022년 7월 29일
4
post-custom-banner

코드스테이츠에서 제공해준 심플한 샘플 블로그에 이론으로 배운 Custom Hook, lazy, Suspense 함수를 코드로 직접 사용하여 동작방식 확인한다.
https://github.com/2-phones/fe-sprint-react-hooks

가짜 REST API 서버를 이용하여 json 데이터를 직접 받아와 실제 블로그처럼 되도록 코드를 작성한다.
먼저 가짜 서버를 설치한다.

 // json-server라는 라이브러리로, json 파일을 이용하여 REST API 서버를 구축해주는 라이브러리이다.

$ npm i -g json-server
$ cd data 
$ json-server --watch data.json --port 3001

json 파일이 있는 data 폴더에서 서버를 실행시키고 json 파일을 이용하여
get,post 요청시 그에 맞게 응답해주는 형식이다.

먼저 app.js 에서 Route 설정한 컴포넌트를 layz 로 바꾸고 Suspense로 감싼다.

import Home './Home'
import CreateBlog './blogComponent/CreateBlog'
import BlogDetail './blogComponent/BlogDetail'
import NotFound './component/NotFound'

// 기존에 있던 위의 코드 불러오기를 지우고 밑에 코드를 추가한다.

import React, { Suspense, lazy } from 'react';

const Home = React.lazy( () => import('./Home'))
const CreateBlog = React.lazy( () => import('./blogComponent/CreateBlog'))
const  BlogDetails = React.lazy( () => import('./blogComponent/BlogDetail'))
const NotFound = React.lazy( () => import('./component/NotFound'))

 <Suspense fallback={<div>로딩...</div>}>
   <Routes>
       // ...생략
   </Routes>
 </Suspense>

작성된 내용 클릭시 세부내용 화면 띄우기

useParams로 작성한 내용의 id값을 받아와 해당 id 내용만 화면에 띄우도록한다.


const BlogDetails = () => {

  const {id} = useParams();
  const request = { 
    method : "get" , 
    headers : {'Content-Type': 'application/json'},
  }
  
  fetch(`http://localhost:3001/blogs${id}`, request)
  .then(res => res.data)
  .cath( err => console.log(err) )

블로그 내용 추가하기

게시글 작성 버튼을 클릭하여 제목, 내용 , 작성자 값을 서버에 post 요청하여 생성 할수 있도록 한다.

const CreateBlog = () => {
    const [title, setTitle] = useState('');
    const [body, setBody] = useState('');
    const [author, setAuthor] = useState('김코딩');
    const navigate = useNavigate();

    const handleSubmit = (e) => {
        e.preventDefault();
 
      const bodys = { title,body,author,likes:0 };
      const request = {
      	method:"POST",
        body : JSON.stringify(bodys),
        headers: {'Content-Type': 'application/json'}
      }

        fetch('http://localhost:3001/blogs',request)
        .then( () => {
          navigate('/')
          window.location.reload();
        })
        .catch( err => console.log(err));
       console.log(e.type);
    }

가짜 서버를 이용하고 있어서 새로고침을 하지 않으면 생성된게 보이지 않는다. 그래서
window.location.reload() 메서드를 사용하여 정상 응답을 받으면 새로고침 되도록했고, navigate( '/') 처음 화면으로 자동으로 이동하여 화면에 잘보인다.

삭제버튼 , 하트버튼

삭제버튼 클릭시, 해당 정보 삭제되고 하트버튼 클릭시 하트 수가 증가하도록 기능 구현한다.

// 삭제버튼
const handleDeleteClick = () => { 
const {id} = useParams();
const [isLike, setIsLike] = useState(true);
   fetch(`http://localhost:3001/blogs/${id}`, {
     method : "DELETE",
     headers: {'Content-Type': 'application/json'},
   })
   .then( () => {
     navigate('/')
     window.location.reload()
   })
   .catch( err => console.log(err))
 }

// 하트버튼
const handleLikeClick = () => {
   // 하트를 누르면 home에서 새로고침을 했을 때 숫자가 올라가야 합니다.
	// isLike false 인경우 true 로 바뀐다.
   setIsLike(!isLike);
   let likeUpdate = blog.likes 
  
   // isLike state가 false 이고 ,0보다 큰경우 하트 수 감소하고 , true면 증가  
   isLike === false ? 
   ( likeUpdate > 0 ? likeUpdate = blog.likes -1 : likeUpdate = blog.likes  ) 
   : likeUpdate = blog.likes +1

   const putData = {  // 기존 데이터를 덮어씌우기 때문에 데이터 전부다 보내줘야한다.
     'id' : blog.id,
     "title" : blog.title,
     "body" : blog.body,
     "author" : blog.author,
     "likes" : likeUpdate,
   }
   console.log(likeUpdate)
   fetch(`http://localhost:3001/blogs/${id}`,{
         method:"PUT",
         body : JSON.stringify( putData ),
         headers: {
           'Content-Type': 'application/json'
       },
       })
       .then( () => {
         navigate(`/blogs/${blog.id}`)
  
       })
       .catch( err => console.log(err) )
 }

마지막 Custom Hook 생성

GET 메소드를 통해 데이터를 받아오는 useEffect hook은 컴포넌트 내 여기저기 존재하고 있다. 해당 hook은 반복이 되는 부분이 있으므로 Custom Hook 을 만들어 적용시킨다.

export const useFetch = (url) => {
  const [blogs, setBlogs] = useState(null);
  const [isPending, setIsPending] = useState(true);
  const [error, setError] = useState(null); 
  /* useState를 이용하여 data, isPending, error를 정의하세요. */

  /* useFetch 안의 중심 로직을 작성해주세요. */
  useEffect(() => {
    setTimeout(() => {
      fetch(url)
      .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);
      })
    }, 500);
  }, [])
  return {blogs , isPending , error,} 
}

조회를 하려는 곳에서 간편하게 디스트럭처링 문법으로 할당한다음 활용 할수있다.

const {blogs, isPending, error,} = useFetch('http://localhost:3001/blogs');

<h2>{ blog.title }</h2>
<p>Written by { blog.author }</p>
<div>{ blog.body }</div>
{!isLike? '❤️' : '🤍' }

profile
Run Start 🔥
post-custom-banner

0개의 댓글