제가 처음 리액트를 공부할 때 리덕스는 넘어야만 하는 큰 산 중에 하나였습니다. 상태 관리를 해야 했으니까요. 하지만 '상태를 변경한다' 라는 목적만을 갖고 봤을 때 리덕스가 사용하고 있는 방식은 다소 난해하게 느껴졌습니다. 리덕스를 사용하기 위해서는 최소 리듀서와 액션 생성 함수, 그리고 상태를 사용하는 컴포넌트가 필요합니다.
리듀서: 초기 상태를 정의하고 액션이 발생했을 때 데이터가 어떻게 변하는지를 정의함
액션 생성 함수: 액션이 발생하면 디스패치를 통해 실제 상태를 변경함
컴포넌트: 상태를 사용함
클라이언트에서 만들고 사용하는 상태의 경우 이렇게 간단한 파일 몇 개로 리덕스를 구현할 수 있습니다. 리덕스 예제로 많이 나오는 카운터처럼요. 하지만 클라이언트에서 사용하는 상태를 서버에서 받아와야 한다면, 서버에서 받아온 데이터를 가공해야 한다면, 리덕스의 구조는 점점 더 복잡해지게 됩니다. 이때 사용하는 것이 미들웨어입니다. react-thunk나 react-saga와 같은 라이브러리입니다.
프로젝트가 점점 커지게 될 경우, 하나의 상태를 받아오고 사용하고 변경하기 위해 리듀서, 액션 생성 함수, 미들웨어를 다 작성해줘야 하는 번거로움이 발생하게 됩니다. 그리고 이 경우 프로젝트의 구조가 복잡해지는 것뿐만 아니라 프로젝트를 한 눈에 파악하기도 어려워집니다.
이러한 번거로움을 해결하기 위해 지금은 많은 개발자들이 data-fetching 라이브러리를 사용합니다. SWR이나 react-query와 같은 라이브러리입니다.
저는 그 중에서도 SWR에 대해서 설명하려고 합니다. 제가 지금 실제로 사용하고 있는 라이브러리이기 때문입니다. 제가 근무하고 있는 회사에서는 어떤 프로젝트에서는 리액트에 리덕스를 사용하고, 어떤 프로젝트에서는 앵귤러를 사용하고, 또 어떤 프로젝트에서는 next.js에 SWR을 사용합니다. 세 가지 모두 경험해보고 느낀 점은, SWR이나 react-query를 많은 회사들이 채용하고 있는 이유를 알 것 같다는 점이었습니다.
제가 느낀 SWR의 장점은 다음과 같습니다.
1. 변경된 데이터가 있는 경우 해당 데이터를 사용하는 모든 컴포넌트에 함께 적용된다.
2. 데이터를 받아오는데 실패할 경우 재호출 등의 추가 동작을 쉽게 할 수 있다.
3. 데이터가 변경된 경우 바로 fetch할 수 있다.
SWR을 이용해 데이터를 가져오는 것은 간단합니다. 어떤 url을 사용해 데이터를 가져올지만 정의해주면 됩니다. 또한 SWR을 사용하면 데이터를 받아오고 업데이트하는 일련의 과정을 커스텀 훅으로 정의하고 필요할 때마다 데이터를 꺼내 쓸 수 있게 됩니다. 데이터를 변경하는 컴포넌트와 사용하는 컴포넌트를 완전히 분리시킬 수 있습니다. 아래와 같이 SWR로 받아온 데이터를 사용하는 컴포넌트가 있을 경우,
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', url => {
return fetch(url).then(res => res.json());
})
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
이렇게 커스텀 훅으로 분리할 수 있습니다. 이렇게 정의한 커스텀 훅은 앞으로 users의 정보를 가져와야 하는 컴포넌트에서 필요에 따라 데이터를 사용할 수 있도록 import할 수 있습니다.
import useSWR from 'swr'
export default () => {
const {data, error} = useSWR('/api/users', url => {
return fetch(url).then(res => res.json());
});
return { data, error };
}
SWR은 mutate라는 함수를 이용해 데이터를 갱신합니다. 만약 데이터에 어떤 변경 사항이 있을 경우 이 데이터가 바로 변경되어 사용자에게 보여져야 하는데, 이럴 때 mutate를 사용합니다.
import useSWR from 'swr'
function UserInfo(){
const {data, error, mutate} = useSWR('/api/users', url => {
return fetch(url).then(res => res.json());
});
const handleChange = async (user) => {
await updateUser(user);
return mutate();
}
return { data, error, handelChange };
}
SWR에서는 데이터를 refetch하거나 또는 하지 않을 때 사용할 수 있는 옵션들을 제공합니다. refetch가 필요없을 때는 refetch를 하지 않도록 옵션을 정하고, 특정 상황에서 refetch 되어야 할 경우에는 해당 옵션을 정의할 수 있습니다.
와 같은 다양한 옵션들이 있고, 해당 옵션들에 대해 자세히 안내하고 있습니다. (swr 옵션 알아보기)
리덕스를 사용하다가 SWR을 사용하게 되었을 때 그 편의성에 놀랐던 기억이 있습니다. 그래서 SWR에 대해 정리를 해보고자 포스팅을 작성했습니다. 그 과정에서 제가 잘 활용하지 못했던 옵션들에 대해서도 공부하게 되었습니다. 포스팅을 하면서 알게 된 것들을 실제로 활용해봐야겠다는 생각이 듭니다.
Redux 를 넘어 SWR 로
React에서 서버 데이터를 최신으로 관리하기(React Query, SWR)
SWR 더 깊이 톺아보기
axios 외길인생, swr을 만나다.