리덕스.. 부터 react-redux, RTK까지 .. 오느라 참 힘들었씁니다.. 이게 2주나 걸릴 줄이야..
우리는 리덕스의 3가지 규칙을 배웠습니다.
- 상태는 read-only이다.
- 하나의 애플리케이션에는 스토어가 1개이다. (리듀서도.. 1개이다. 실은combine해주니까)
- 리듀서는 순수 함수이다.
우리는 store에 상태를 변환시키기 위한 로직을 리듀서 함수내에서 적어줬었죠,
툴킷을 쓰기 이전에는 switch 문으로 action.type을 나눠서 로직을 적고,
툴킷을 쓰게 된다면 reducers라는 객체에 로직을 적어주었습니다.
하지만 리듀서함수는 순수함수여야한다고 했습니다.
따라서 비동기적인 로직은 리듀서 함수에 적을 수 없습니다.. 않의 그럼 어케 이거 비동기 처리 할 수 있다는 고임?
따라서 비동기 처리 로직은 모두 action 생성 함수에서 처리합니다.
● 로직 처리 방법
- 동기적인 로직들은 모두 리듀서함수에서 처리합니다.
- 비동기 로직들은 모두 action creators 즉, 생성자 함수나 아니면 컴포넌트 내에서 합니다.
왜냐고요? 리듀서함수는 순수함수여야하기 때문에 리듀서에서 비동기적인 로직을 짤 수 없기 때문입니다!
● 컴포넌트에서 비동기 로직 짜보기
비동기 로직을 짜서, store의 상태를 변환시키는 방법에는 컴포넌트에서 로직을 짜고 dispatch하거나, 아니면 action 생성자함수에서 비동기 로직을 짜고 dispatch하는 방법입니다.
먼저 컴포넌트에서는 어떻게 비동기 로직을 짜야할까요?
예를 들어, 쇼핑몰 페이지가 있습니다.
내가 장바구니에 물건을 담을 때마다, 물건의 종류와 개수를 데이터베이스에 저장해야합니다.
따라서 store가 변경될 때마다 데이터 베이스에 데이터를 옮겨야한다는 뜻입니다.
● useEffect로 사용한 로직
이는 useEffect로 활용하여 해결할 수 있습니다.
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
const Componenet = ({number}) => {
const cart = useSelector(state => state.cart);
useEffect(()=>{
fetch(~~~url, {
method : 'PUT',
body : JSON.stringify(cart),
})
} , [cart])
return (...)
}
export default Component
- useSelector로 스토어의 state를 가져옵니다. 즉 구독의 형태가 됩니다.
- useEffect의 의존성 배열에 state, 즉 cart를 넣어줌으로써, store가 변경될 때마다 fetch요청을 할 수 있게 됩니다.
- 데이터베이스에 method는 'PUT'으로 넣어 카트에 아이템이 담기게 되거나 없어진다면 기존 데이터에 오버라이드 해줍니다.
위와 같은 양식으로 적어준다면 store가 변경될 때마다 fetch요청을 할 수 있습니다.
즉 순서를 정리하자면,
액션을 보내서 리듀서 함수를 통해 store 변환 > useEffect내부에서 fetch요청
이라고 할 수 있습니다.
하지만 이 방법에서의 오류는 뭘까요?
만약 처음에 페이지가 로드되었을 때, 처음 상태를 fetch요청을 하게 되고, 오버라이드 하기 때문입니다.
마지막에 내가 카트에 넣었던 물건이 만약에 생수 6개였다면 다시 페이지를 닫고 다시 들어왔을 때 카트가 비어있다면 데이터베이스에는 카트에 아무것도 없는 상태가 오버라이드 되게됩니다. 즉, 생수 6개 담은것을 기억하지 못하게 된다는 거죵.
따라서 만약에 페이지를 처음 로드한거라면 true, false 이런식으로의 변수를 새로만들고 새로로드되었을 때에는 데이터 베이스에 있는 값을 가져와 store에 저장을 해주고,
아니라면 store의 상태가 변할 때마다 데이터베이스에 저장을 해준다. 식으로 진행해주면 됩니다.
이외에는 이제.. 리덕스 미들웨어를 사용할 수 있습니다.
● redux-thunk 미들웨어
redux-thunk는 컴포넌트가 아니라 action-creators 즉, 생성자 함수에서 비동기 로직을 짜는 것 입니다.
컴포넌트에서는 어떠한 비동기 로직을 하고, dispatch를 할 수 있지만 액션 생성자 함수에서는 dispatch를 할 수 없었습니다.
따라서 미들웨어를 사용하게되는데요, thunk 미들웨어의 양식은 아래와 같습니다.
const createThunk = () => dispatch => {
dispatch({어쩌구저쩌구});
}
thunk 액션 생성 함수에서는 객체를 반환하는 것이 아니라 함수를 반환합니다.
그리고 반환하는 함수는 dispatch함수를 매개변수로 받을 수 있습니다. 따라서 컴포넌트에서 dispatch를 했던 것처럼, thunk 액션 생성자 함수에서도 dispatch를 할 수 있게 되는 것입니다.
따라서 위의 예시처럼 비동기 로직을 안에서 짤 수 있게 됩니다..!!
const createThunk = () => async dispatch => {
dispatch({어쩌구저쩌구});
}
비동기 로직을 짜고 싶다면 반환하는 함수 앞에 async를 붙여 안에 비동기 로직을 짜면 됩니다..!