리덕스의 리듀서 함수에는 중요한 규칙이 하나 존재한다.
- 반드시 순수함수이며, 사이드이펙트가 없고, 동기식이어야한다.
하지만 웹 애플리케이션을 구축하다보면, 필수적으로 사이드이펙트 & 비동기 코드가 들어가야할때까 존재한다.
이럴때는 어떻게 처리해야할까?
이 글에서 알아볼 것
- Redux에서 SideEffect & Async 사용 방법
- Redux에서 SideEffect & Async - 컴포넌트
- Redux에서 SideEffect & Async - 액션 생성자
1. Redux에서 SideEffect & Async 사용 방법
리덕스에서 사이드이펙트 & 비동기 코드를 사용하는 방법은 2가지이다.
- 컴포넌트에서 처리
- 컴포넌트에서 사이드이펙트등이 처리된 후에만, 리덕스에게 액션을 보낸다
- 따라서, 리덕스는 사이드이펙트등의 존재를 알수없다
- 액션 생성자에서 처리
- 대신, 리덕스 툴킷이 자동으로 생성해주는 기능 사용하지 못한다
이러면 들수있는 의문이,
그냥 사이드이펙트나 비동기코드는 컴포넌트에서 모든걸 처리하면되는거 아닌가 싶을수있다.
(굳이 리덕스를 활용하지 않고)
하지만, 사이드이펙트와 비동기코드를 사용하는 경우는 주로 백엔드와의 통신에서 사용되는데,
이때, 프론트엔드 코드와 백엔드 코드를 정확히 분리하여 구조를 짜는것이 중요하다.
- 예를들어 firebase등과 같이 백엔드에서 많은일 해주지 못할때는 필연적으로 프론트에 많은 로직이 들어갈텐데, 이때 이 로직들을 컴포넌트에 다 작성하는 것은 권장되지않는다
- 왜냐하면 우리는 리덕스를 사용하고있으니까, 리덕스를 충분히 활용하는 것이 바람직하다,, 따라서 상대적으로 무거운 로직들은 리덕스에서 처리하도록 구조를 잡는것이 더 좋은 코드일것이다.
2. Redux에서 SideEffect & Async - 컴포넌트
이 방법은 앞에서 살펴본것과 같이 특정 컴포넌트에서 사이드이펙트와 비동기코드 관련 로직을 작성한 후,
리덕스에게 알려주면된다.
let isInitial = true;
function App() {
const dispatchFn = useDispatch();
const showCart = useSelector((state) => state.ui.cartIsVisible);
const cart = useSelector((state) => {
return state.cart;
});
const notification = useSelector((state) => {
return state.ui.notification;
});
useEffect(() => {
const sendCartData = async () => {
dispatchFn(
uiActions.showNotification({
status: "pending",
title: "Sending...",
message: "Sending cart data",
})
);
const response = await fetch("https://react-customhooks-22616-default-rtdb.firebaseio.com/cart.json", {
method: "PUT",
body: JSON.stringify(cart),
});
if (!response.ok) {
throw new Error("Error!");
}
const data = await response.json();
dispatchFn(
uiActions.showNotification({
status: "success",
title: "Success!",
message: "Sent cart data successfully",
})
);
};
if (isInitial) {
isInitial = false;
return;
}
sendCartData().catch((err) => {
dispatchFn(
uiActions.showNotification({
status: "error",
title: "Error...",
message: "Sending cart data failed",
})
);
});
}, [cart, dispatchFn]);
3. Redux에서 SideEffect & Async - 액션 생성자
Thunk라는 함수를 이용하면된다.
- Thunk란?
- 다른 작업이 완료될때까지 작업을 지연시키는 단순한 함수
export const sendCartData = (cart) => {
return async (dispatchFn) => {
dispatchFn(
uiActions.showNotification({
status: "pending",
title: "Sending...",
message: "Sending cart data",
})
);
const sendRequest = async () => {
const response = await fetch("https://react-customhooks-22616-default-rtdb.firebaseio.com/cart.json", {
method: "PUT",
body: JSON.stringify(cart),
});
if (!response.ok) {
throw new Error("Error!");
}
const data = await response.json();
};
try {
await sendRequest();
dispatchFn(
uiActions.showNotification({
status: "success",
title: "Success!",
message: "Sent cart data successfully",
})
);
} catch (error) {
dispatchFn(
uiActions.showNotification({
status: "error",
title: "Error...",
message: "Sending cart data failed",
})
);
}
};
};
// 컴포넌트
useEffect(() => {
if (isInitial) {
isInitial = false;
return;
}
dispatchFn(sendCartData(cart));
}, [cart, dispatchFn]);
'OLD > React' 카테고리의 다른 글
[ React ] react-router loader vs react-query useQuery (0) | 2023.08.22 |
---|---|
[React] 여전히 create-react-app을 사용 해야 할까? (CRA vs VITE) (0) | 2023.05.22 |
[React] React Redux_02 (Redux Toolkit) (0) | 2023.03.05 |
[React] React Redux_01 (Redux 기본) (0) | 2023.03.05 |
[React] React Context (useContext) (0) | 2023.03.03 |