I have some component with a code like this:
const startLogin = (code) => {
dispatch(login({ code }));
const publicKeyFromLocalST = window.localStorage.getItem('push_public_key');
setPublicKey(publicKeyFromLocalST);
// etc
When I dispatch the saga login
it will store some data in localStorage.
I need to execute the 3rd line (setPublicKey
) after that data be actually indeed in localStorage.
How can "await" for dispatch(login({ code }));
to be completed before setPublicKey?
Two options:
setPublicKey
function inside the worker saga, you can control the workflow in the worker saga easily with yield
.function* login(action) {
const response = yield call(apiCall);
if (response.error) {
yield put({ type: actionType.LOGIN_FAIL });
} else {
yield put({ type: actionType.LOGIN_SUCCESS, data: response.data });
const publicKeyFromLocalST = window.localStorage.getItem('push_public_key');
setPublicKey(publicKeyFromLocalST);
}
}
dispatch(login({code}))
, you should create a helper function like this:const loginAsyncCreator = (dispatch) => (payload) => {
return new Promise((resolve, reject) => dispatch(loginCreator(payload, { resolve, reject })));
};
You need to pass the resolve
/reject
to worker saga via action.meta
, then you can decide when to resolve or reject the promise. Then, you can use async/await
in your event handler. See below example:
import { call, put, takeLatest } from 'redux-saga/effects';
import { createStoreWithSaga } from '../../utils';
const actionType = {
LOGIN: 'LOGIN',
LOGIN_FAIL: 'LOGIN_FAIL',
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
};
function apiCall() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ error: null, data: 'login success' });
}, 2000);
});
}
function* login(action) {
console.log('action: ', action);
const {
meta: { resolve, reject },
} = action;
const response = yield call(apiCall);
console.log('response: ', response);
if (response.error) {
yield put({ type: actionType.LOGIN_FAIL });
yield call(reject, response.error);
} else {
yield put({ type: actionType.LOGIN_SUCCESS, data: response.data });
yield call(resolve, response.data);
}
}
function* watchLogin() {
yield takeLatest(actionType.LOGIN, login);
}
const store = createStoreWithSaga(watchLogin);
function loginCreator(payload, meta) {
return {
type: actionType.LOGIN,
payload,
meta,
};
}
const loginAsyncCreator = (dispatch) => (payload) => {
return new Promise((resolve, reject) => dispatch(loginCreator(payload, { resolve, reject })));
};
const loginAsync = loginAsyncCreator(store.dispatch);
async function startLogin() {
await loginAsync({ code: '1' });
console.log('setPublicKey');
}
startLogin();
The logs:
action: {
type: 'LOGIN',
payload: { code: '1' },
meta: { resolve: [Function (anonymous)], reject: [Function (anonymous)] }
}
response: { error: null, data: 'login success' }
setPublicKey