일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- SCSS import
- KDT 프로그래머스
- Vue
- vuex map
- 리스트 렌더링
- git 같은계정 다른 컴퓨터
- 프로그래머스 K_Digital Training
- SCSS use
- 프로그래머스 데브코스 프론트엔드
- SCSS extend
- 폼 입력 바인딩
- vue mixin
- 다른컴퓨터에서 git사용
- KDT 프로그래머스 데브코스 프론트엔드
- 쌓임맥락
- SCSS forward
- netlify redirect
- 프로그래머스 데브코스
- 프로그래머스 프론트엔드 데브코스
- 리액트
- nextjs사용법
- react next
- Spacer
- postcss
- 고양이 사진 검색기
- intersection opserver
- vue 지역 컴포넌트
- flex
- vue 이벤트 수신
- 이벤트 수식어
- Today
- Total
혼자 적어보는 노트
[Redux] Redux-saga 사용 해보기 본문
지난 포스팅에서 generator에 대해 아주 기본적인 부분들을 이해 한 후에
saga를 해보기로 했고 로그인 기능을 예제로 작성하였다.
💡 redux-saga를 사용하는 이유
redux의 dispatch는 동기적으로 이루어지며 dispatch를 나누어서 해야할 경우
컴포넌트가 담긴 파일 내부에서 dispatch를 여러번 작성을 해야하는 불편함이 있다.
아주 기본적인 비동기처리를 위해서는 thunk만 사용해도 되지만 기능이 제한적이다.
redux-saga는 비동기적으로 dispatch를 사용할 수 있을 뿐만 아니라
내부 메소드에 api의 연속호출을 제어하는 (debounce, throttle) 등 다양한 기능들을 활용할 수 있다.
설치
npm i redux-saga
saga 사용 해보기
store 생성
store.js
import { applyMiddleware, createStore } from "redux";
import reducer from "../reducers/index";
import createSagaMiddleware from "@redux-saga/core";
import rootSaga from "../sagas";
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware(); // saga 생성
const middleware = [sagaMiddleware]; //saga 추가
const store = createStore(reducer, applyMiddleware(...middleware));
store.sagaTask = sagaMiddleware.run(rootSaga); //sagaTask에 담기
return store;
};
export default configureStore;
사가 미들웨어를 생성하고, 미들웨어에 사가를 담고
스토어에 미들웨어를 추가하는 방식이다.
rootSaga만들기
여러개의 사가를 관리할 수 있게 rootSaga를 생성한다.
sagas/index.js
import { all, fork } from "redux-saga/effects";
import userSaga from "./user";
export default function* rootSaga() {
yield all([fork(userSaga)]);
}
userSaga 만들기
import { all, call, fork, put, takeLatest } from "redux-saga/effects";
import axios from "axios";
function logInAPI(data) {
// 여기는 제너레이터가 아님!
return axios.post("/api/login", data);
}
function* login(action) { // (3)
try {
//API 통신에는 call을 사용
const result = yield call(logInAPI, action.data);
yield put({
type: "LOG_IN_SUCCESS",
data: result.data,
});
} catch (error) {
yield put({
type: "LOG_IN_FAILURE",
data: error.response.data,
});
}
}
function* watchLogIn() { // (2)
yield takeLatest("LOG_IN_REQUEST", login);
}
export default function* userSaga() { // (1)
yield all([
fork(watchLogIn) //watch함수 추가 생성 시 배열안에 담아준다.
]);
}
1. rootSaga를 만들어주는데 여기서
all은 배열을 인자로 받으며 배열 안에 담긴 함수들을 동시에 실행시켜준다.
여기서 fork는 함수를 호출하는 의미로 사용된다.
2. watchLogin은 login action을 대기하는 함수이다.
takeLatest는 LOG_IN_REQUEST action이 실행되면 두 번째 인자의 함수를 실행한다.
즉, LOG_IN_REQUEST action이 실행되면 login함수를 실행한다.
* takeLatest는 연속적으로 호출했을 경우 마지막 호출을 한 것에 대해서 한번의 응답을 받는다.
3. login은 action을 인자로 받으며 loginAPI에 action.data를 보내서 실행하고 그 값을 result에 담는다.
call은 동기 함수 호출을 의미하며 loginAPI가 retuen할 때까지 기다린다.
성공/실패의 여부에 따라 put을사용해서 새로운 action을 보낸다.
구조가 async await문법과 비슷하며 put은 dispatch와 비슷하다.
*모두 제너레이터 문법을 사용하지만 api를 호출하는 함수는 일반 함수이다.
*effect 앞에는 yield를 붙여주어야 한다.
saga는 비동기 액션 크리에이터를 직접실행하는 것이 아니라
이벤트처럼 받아서 실행을 한다.
그럼 리듀서를 생성해보자.
reducer.js
export const loginRequestAction = (data) => {
return { type: "LOG_IN_REQUEST", data };
//여기서의 return값이 login의 매개변수로 전달된다.
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "LOG_IN_REQUEST":
return {
...state,
isLoading: true,
};
case "LOG_IN_SUCCESS":
return {
...state,
currentUser: { ...action.data },
isLoading: false,
isLoggedIn: true,
};
case "LOG_IN_FAILURE":
return {
...state,
isLoading: false,
isLoggedIn: false,
};
default:
return state;
}
};
export default reducer;
dispatch를 받을 loginRequestAction 액션함수를 생성하고
reducer에 요청과 성공, 실패에 대한 내용을 작성해준다.
요청을 받았을 때 어떤 순서로 진행이 되는지 그려보기
사용자의 액션을 통해 dispatch(loginRequestAction(data))가 발생되면
reducer의 case "LOG_IN_REQUEST": 이 실행됨과 동시에
saga에서 watchLogin으로 대기하고있던 login함수에 action data가 전달되며 실행되고
login함수 내부에 작성해 놓은 코드대로 성공과 실패에 따라 다른 dispatch요청을 보내게된다.
✨ saga effects ✨
all : 배열을 받으며 안에 담긴 함수들을 동시에 실행시켜 준다.
fork : fork는 비동기 함수 호출. 즉 일반 함수 호출과 같다.
call : 동기 함수 호출. api요청함수 전달 시 retuen할 때까지 기다린다. 첫 번째 인자는 호출할 함수, 두 번째인자는 함수의 매개변수
put : dispatch를 보내는 함수
take : 첫 번째 인자에 적은 action이 실행될 때 까지 기다리고 action이 실행되면 두 번째 인자인 함수를 실행한다.
* take는 1번만 실행되고 삭제된다.
takeEvery : take와 같지만 계속 실행시킬 수 있다.
takeLatest : 계속 실행시킬 수 있으며, 요청을 2번 했을 때 마지막 이벤트를 실행한다.
* front에서 서버로 요청을 2번 보내지만 응답만 1번 받는 것이기 때문에 서버에서도 중복을 막아주어야 한다.
takeLeading : takeLatest와 반대로 요청을 두번 했을 때 첫 번째 이벤트만 실행한다.
throttle : 지정한 초 이내에 요청을 1번만 보낼 수 있다. trottle(액션명, 함수, delay할 초)
debounce : 연속으로 호출될 경우 가장 마지막 호출이 적용된다.
하면서 겪은 에러
import를 제대로 하지 않아서 생긴 에러
(0 , redux_saga__WEBPACK_IMPORTED_MODULE_1__.fork) is not a function
fork, all, put 등의 effects들을 redux-saga/effects가 아닌 from 'redux-saga' 에서 불러올 시
위와 같은 에러가 발생한다,.
'기타' 카테고리의 다른 글
회원가입 구현하기 /NextJS, Express, MySQL (0) | 2022.03.18 |
---|---|
[MySQL] sequelize mysql column 이름, 속성 변경 및 생성 (0) | 2022.03.18 |
[VSCode] prettier 설정 변경 / 줄바꿈 / 따옴표 변경 (0) | 2022.03.06 |
target="_blank"의 문제점 / noopener noreferrer 사용 (0) | 2022.03.01 |
브라우저의 렌더링 원리, 과정 (0) | 2022.02.26 |