반응형
리액트에서 전역상태관리를 하기 위해 redux라는 라이브러리를 사용했었는데 코드의 양도 많고 여러가지 불편한 점이 하나씩 보이기 시작하면서 새로운 라이브러리를 찾게 되었다. 요즘 많이 쓰고 있다는 React-query와 SWR이라는 라이브러리를 알게 되었는데 두가지 중 먼저 시도해보고자 했던 것이 SWR이었다.
리덕스 사용시 불편했던 점
- 리덕스 흐름에 따라 (View -> Dispatch -> Action -> Reducer -> Store -> State) 작성해야하는 코드의 양이 많음
- 한번 가져왔던 정보라도 컴포넌트가 마운트 될 때마다 새로 가져와서 갈아끼우는 작업이 비효율적
- 지속적으로 리덕스 로컬 스토어의 상태를 서버 상태와 맞추기 위해 추가적으로 동기화 작업을 해줘야함
그래서 SWR이란?
SWR은 Next.js로 유명한 vercel에서 만든 원격데이터 fetch를 위한 커스텀 훅 npm 모듈로 원격 서버의 상태를 가져와 리액트 컴포넌트에 넘겨주는 기능을 제공하는데 리액트 훅 라이브러리라고 생각하면 될 것 같다.
useSWR 은 첫번째 인자로 원격 상태에 대한 key를 넘겨주고 두번째 인자로 데이터 fetch 함수를 받는다.여기서 첫번째 인자는 두번째 fetch 함수의 첫번째 인자로 전달되는데 fetch함수가 데이터를 로드하면 해당 응답이 data로 세팅되고 오류가 발생할 경우 해당 오려고 error에 세팅된다. 그렇기 때문에 컴포넌트에서는 data와 error 상태에 따라 알맞게 결과를 렌더링 해주면 된다.
SWR 적용방법
1. npm을 통해 설치하거나 yarn을 이용한다면 yarn을 이용해 swr을 설치하자
yarn add swr
npm install swr
2. fetcher 함수 생성
import axios from 'axios';
const fetcher = url => axios.get(url).then(res => res.data);
export default fetcher;
3. 함수형 컴포넌트에서 useSWR을 임포트하고 사용하면 된다.
- date와 error를 받으며 error가 있을 때 ERROR라는 코드를 보여주고 데이터가 아직 내려오지 않은 로딩중 상태일 때는 Spinner를 적용하여 보여준다.
import useSWR from "swr";
import fetcher from "../shared/Fetcher";
import Spinner from '../elements/Spinner';
const BookDetail = () => {
// 책 상세페이지 정보 가져오기
const { data, error } = useSWR(process.env.REACT_APP_BASE_URL + `/book/detail/${bookId}`, fetcher)
if (error) {
return <div>ERROR...</div>
}
if (!data) {
return <Spinner/>
}
return (
<React.Fragment>
<Wrap>
<Header>
<p>{data.title}</p>
<span>{data.author}</span>
</Header>
<BookInfo>
<ImgBox style={{ backgroundImage: `url(${data.bookImg})` }}>
<div id='img_wrap'>
<div id='img'>
<img src={data.bookImg} alt="책 이미지" />
</div>
</div>
</ImgBox>
<Content>
<div>
<p>이 오디오북에 참여한 크리에이터</p>
<p><span>{data.audio ? data.audio.length : 0} </span>명</p>
</div>
<div>
{authority === "ROLE_SELLER" ?
<>
<button
onClick={() => {
history.push(`/fundingWrite/${bookId}`)
}}>
내 펀딩 등록하기
</button>
<button
onClick={() => {
dispatch(fundingActions.fundingSuccessAC(bookId, category));
}}>
내 오디오 등록하기
</button>
</>
:
null
}
<button
onClick={() => {
if (!is_login) {
Swal.fire({
text: "로그인 후 이용 가능합니다!",
icon: "warning",
confirmButtonText: "로그인하러가기",
confirmButtonColor: '#0C0A0A',
}).then(result => {
if (result.isConfirmed) {
history.push(`/login`)
}
})
} else {
dispatch(libraryActions.addLibraryAC(bookId));
}
}}
>내 서재에 담기</button>
</div>
</Content>
</BookInfo>
<AudioBookBox>
<AudioBookList detail={data} />
</AudioBookBox>
<BookSum>
<span id='bookinfo'>
책 정보
</span>
<div>
<span style={{ whiteSpace: "pre-wrap", wordBreak: 'keep-all', lineHeight: "1.5", }}>
{data.summary}
</span>
</div>
</BookSum>
</Wrap>
</React.Fragment>
)
}
export default BookDetail;
반응형