9-non-blocking
function* loginFlow() {
while (true) {
yield take('LOGIN')
// ... perform the login logic
yield take('LOGOUT')
// ... perform the logout logic
}
}function* authorize(user, password) {
try {
const token = yield call(Api.authorize, user, password)
yield put({type: 'LOGIN_SUCCESS', token})
return token
} catch(error) {
yield put({type: 'LOGIN_ERROR', error})
}
}
function* loginFlow() {
while (true) {
const {user, password} = yield take('LOGIN_REQUEST')
const token = yield call(authorize, user, password)
if (token) {
yield call(Api.storeItem, {token})
yield take('LOGOUT')
yield call(Api.clearItem, 'token')
}
}
}위 코드의 문제점은 사용자가 로그인 버튼 누르고 기다리는 동안, 즉, Api.authroize가 오랜시간 펜딩 중일 때.. 이 때, loginFlow가 authorize 호출에 의해 block 되어 있음.
사용자가 못참고 로그아웃을 누르면 LOGOUT은 무시됨. 왜냐하면 block상태라 yield take('LOGOUT')을 만나지 않았기 때문.
문제 발생 이유는
call 이 blocking 이펙트이기 때문
즉 제너레이터 호출 종료 전까지 아무것도 수행 불가
LOGOUT과authorize은 동시 발생적임authorize 뿐만 아니라, 호출 중간에 일어날 수 있는 우발적인
LOGOUT액션 또한 watch하기를 원함.
문제 해결하려면
authorize논블락킹으로 변경LOGOUT을 계속해서 watch
그래서 fork를 사용해보자.
태스크를 fork하면, 백그라운드에서 진행.
fork된 태스크는 종료될 때까지 진행하지 않고 플로우를 계속해서 진행.
바뀐거
token 받는 로직을 authroize 내부로 이동
fork를 통해 백그라운드 동작이라 결과를 얻을 수 없기 때문
LOGOUT, LOGIN_ERROR를 동시에 watch
아직 남은 문제점
API 호출 도중에
LOGOUT을 받는다면, authorize 프로세스를 취소해야함.그렇게 안하면 2개의 동시 발생적인 태스크가 진행됨
authorize 태스크는 계속 성공 or 실패 결과 기다릴거고
LOGIN_SUCCESS or LOGIN_ERROR를 dispatch해서 엇갈린 상태가 만들어지게됨.
fork된 태스크를 취소하기 위해
cancel을 사용하자.
yield fork는 태스크 오브젝트를 리턴.
또 다른 문제 상황이 있다. 로그인 요청(LOGIN_REQ) 후, isLoginPending flag값을 true로 설정하여 스피너 보여줄 수 있다. 만약 API 호출 도중 LOGOUT을 받고 태스크가 정지된다면, 또다시 엇갈린 상태로 끝남.
cancel 이펙트는 청소 로직을 실행할 기회를 제공
finally 구간안에서 취소 로직 다룰 수 있음
cancelled라는 이펙트를 사용하여 취소로직 생성
그래서
RESET_LOGIN_PENDING을 액션 디스패치 하거나
더 간단한건, LOGOUT 액션에게 리듀서에게 isLoginPending 처리하게 하기.
Last updated
Was this helpful?