오늘은 과제로 React Hooks를 적용해보고, Custom Hook과 React.lazy()와 Suspense를 이용하여
React앱을 리팩토링을 해보았다.
구현해야할 것
json-server 라이브러리 사용
위의 과제에서 데이터로 사용할 것들은 서버를 구축할 필요없이
json 파일을 이용하여 REST API 서버를 구축해주는 라이브러리인 json-server 라이브러리를 사용했다.
json-server는 다른 앱을 만들어볼때도 사용해보았던 기억이 있고, 그때 났었던 에러들을
깃헙 readme에 기록을 해놓은 것이 있어서 에러를 그것을 토대로 잡을 수 있었다.
json-server 라이브러리를 쓰기 위해서는 먼저 설치를 해주어야 한다.
npm i -g json-server
위의 명령어를 이용하여 전역 설치를 해준다. 만약 위의 명령어로 설치가 되지 않고,
아래와 같은 에러가 발생한다면
code EACCES npm ERR! syscall mkdir npm ERR! path /usr/local/lib/node_modules/json-server npm ERR! errno -13
sudo npm i -g json-server
위의 코드를 사용해보면 에러가 나지않고 설치가 정상적으로 될 것이다.
설치가 완료되었다면 json 파일이 있는 data 폴더로 이동한 뒤,
json-server --watch data.json --port 3001
위의 코드를 입력해주어 json-server가 3001번 포트를 점유하고 서버를 열게 해준다.
localhost:3001로 접속해보면 위의 창이 뜨면서 서버가 잘 열린것을 확인할 수 있다.
React.lazy()와 Suspense 적용하기
React.lazy 함수를 사용하여 dynamic import를 사용해 컴포넌트를 렌더링할 수 있다.
즉, 컴포넌트를 동적으로 import를 할 수 있기 때문에 초기 렌더링 지연시간을 어느정도 줄일 수 있다.
React,Suspense를 사용하여 아직 렌더링 준비가 되지 않은 컴포넌트가 있을 때 로딩 화면을 보여주고,
로딩이 완료되면 렌더링이 준비된 컴포넌트를 보여준다.
App.js
위 코드처럼 react.lazy()와 Suspense를 사용하기 위해서는 import를 해주고,
lazy로 감싸주어 dynamic import를 사용하여 컴포넌트를 렌더링할 수 있다.
react.Suspense는 lazy를 통해 import하면 path로 이동할 때 컴포넌트를 불러오는 과정에서
로딩하는 시간이 생기기 때문에 Route 컴포넌트들을 Suspense로 감싸고, fallback속성으로 설정을 해주었다.
작성된 블로그 클릭시 세부내용 화면 띄우기
개별 블로그 내용으로 진입해도 아무것도 뜨지 않기 때문에 useParams를 이용하여
각각 블로그별 id를 받아와서 개별 블로그의 내용을 보여주어야한다.
그렇기 위해서는 BlogDetail.js파일에서
const { id } = useParams();
위의 코드를 통해 각각 파라미터 id값을 받아와서 id값에 맞는 블로그의 내용을 보여줄 수 있다.
fetch를 통해 id에 맞는 블로그의 내용을 get요청을 통해 보여지게 해주었다.
BlogDetail.js
블로그 삭제버튼, 좋아요 버튼
delete 버튼을 누르면 다시 home으로 리다이렉트 되어야하고,
하트를 누르면 home에서 새로고침했을 때 숫자가 올라가야한다.
이 부분도 BlogDetail.js 에서 작성해주었다.
리다이렉트는 useNavigate 훅을 통해서 home으로 리다이렉트 되게 하였고,
window.location.reload()를 통해 새로고침을 해주었다.
좋아요 버튼은 상태를 만들어서 클릭될 때마다 상태가 불리언값인 상태가 변경되게 만들었고,
불리언값이 true냐 false냐에 따라 조건을 나눠주었다.
그리고 PUT으로 좋아요의 수가 바뀐 데이터를 기존의 데이터에 덮어쓰기를 해주었다.
BlogDetail.js
블로그 내용 추가하기
게시글 작성 버튼을 클릭하면 제목, 내용, 작성자, 좋아요 값을 서버에 post 요청하여 생성할 수 있도록 해주었다.
window.location.reload() 를 하지 않으면 진짜 서버가 아니기 때문에 새로고침을 따로 하지않는 이상
새로 생성된게 보이지 않는다. 그래서 reload()메서드를 사용하여 정상 응답을 받아서 .then 메서드 콜백으로
새로고침되고, home으로 리다이렉트되어서 화면에 보이게 된다.
CreateBlog.js
Custom Hook 생성
GET 메서드를 통해 데이터를 받아오는 useEffect Hook이 여러 컴포넌트 내 계속 반복되고 있다.
따라서 이 반복이 되는 부분을 Custom Hook을 만들어서 적용시켜 재사용성과 코드를 간결하게 만들어준다.
useFetch.js
위와 같이 useFetch라는 custom hook을 만들어주고,
GET 메서드를 통해 데이터를 받아오는 useEffect hook을 사용하는 곳에 해당 custom hook을 사용해준다.
useEffect(() => {
setTimeout(() => {
fetch(`http://localhost:3001/blogs/${id}`, request)
.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);
}, [])
BlogDetail.js 와 App.js에서 반복해서 사용중이였던 위의 useEffect hook을
useFetch 라는 Custom hook을 만들어서 재사용성이 쉬워지고 코드로직이 간단해지게 만들어주었다.
위의 useEffect hook 대신 아래의 useFetch hook을 사용하면 된다.
BlogDetail.js
App.js
과제 후 느낀점
아직 Custom hook을 만들고, 적용시켜보는게 너무 어색하고 사실 감이 잘 안잡힌다.
하지만 처음에 커스텀 훅이 뭐야..? 했던 나를 생각해보면 많이 발전했다고 생각한다.
그리고 에러 해결방법이나 몰랐던부분을 블로깅을 통해 기록해두거나, 깃허브readme에 작성해두는게
얼마나 중요하고, 좋은 방법인지 이번 과제를 진행하는 중에 많이 깨달았던 것 같다.
그리고 리액트를 쓰면 쓸수록 js 문법에 대한 중요성을 너무 크게느낀다.
js문법이 아직 덜되어있어서 계속 블로그 찾아가면서 하다보니까 시간도 많이 잡아먹는다.
map, filter, reduce 이런 고차함수는 그냥 나올 수 있게 연습하고,
스프레드 문법, 비구조화 할당, 구조분해 할당 등 리액트에서 엄청나게 자주 사용하는 js문법 많이 공부하고 익히자!