So, I have an epic that receives a SUBMIT_LOGIN action and then it should fire the generateDeviceId function that returns an action with an id as payload. After that is processed by the reducer and the store is updated, it should request the login, then resolve it to store and finally redirect the user to our dashboard
const generateDeviceId = (deviceId) => (({type: GENERATE_DEVICE_ID, payload: deviceId}));
const resolveLogin = (response) => ({type: RESOLVE_LOGIN, payload: response});
const submitLogin = (email, password) => ({type: SUBMIT_LOGIN, payload: {email, password}});
const requestLogin = (email, password) => ({type: REQUEST_LOGIN, payload: {email, password}});
const loadAbout = () => ({type: LOAD_ABOUT});
const submitLoginEpic = (action$) =>
action$
.ofType(SUBMIT_LOGIN)
.mapTo(generateDeviceId(uuidv1()))
.flatMap(({payload}) => login(payload.email, payload.password)
.flatMap(({response}) => [resolveLogin(response.content), loadAbout()])
);
ps: login
function is an ajax
from rx-dom
that returns a stream:
const AjaxRequest = (method, url, data) => {
const state = store.getState();
const {token, deviceId} = state.user;
return ajax({
method,
timeout: 10000,
body: data,
responseType: 'json',
url: url,
headers: {
token,
'device-id': deviceId,
'Content-Type': 'application/json'
}
});
};
const login = (email, password) => AjaxRequest('post', 'sign_in', {email, password});
ps2: uuidv1
function just generates a random key (its a lib)
I think (actually I'm sure) that I'm doing it wrong, but after two days i don't really know how to proceed. :/
UPDATE
After Sergey's first update I've changed my epic to that, but unfortunately for some reason rx-dom's
ajax is not working like Sergey's login$
observable. We're currently working on this.
const generateDeviceId = (deviceId) => (({type: GENERATE_DEVICE_ID, payload: deviceId}));
const resolveLogin = (response) => ({type: RESOLVE_LOGIN, payload: response});
const submitLogin = (email, password) => ({type: SUBMIT_LOGIN, payload: {email, password}});
const requestLogin = (email, password) => ({type: REQUEST_LOGIN, payload: {email, password}});
const loadAbout = () => ({type: LOAD_ABOUT});
const submitLoginEpic = action$ =>
action$.ofType(SUBMIT_LOGIN)
.mergeMap(({payload}) =>
Observable.of(generateDeviceId(uuid()))
.concat(login(payload.email, payload.password)
.concatMap(({response}) => [resolveLogin(response.content), loadAbout()])
UPDATE 2
After Sergey's second update I've changed my code again and ended up with a solution where I use two epics
and .concatMap
operator in order to synchronously
dispatch the actions and it works as expected
.
const generateDeviceId = (deviceId) => (({type: GENERATE_DEVICE_ID, payload: deviceId}));
const resolveLogin = (response) => ({type: RESOLVE_LOGIN, payload: response});
const submitLogin = (email, password) => ({type: SUBMIT_LOGIN, payload: {email, password}});
const requestLogin = (email, password) => ({type: REQUEST_LOGIN, payload: {email, password}});
const loadAbout = () => ({type: LOAD_ABOUT});
const submitLoginEpic = (action$) =>
action$
.ofType(SUBMIT_LOGIN)
.concatMap(({payload}) => [
generateDeviceId(uuid()),
requestLogin(payload.email, payload.password)
]);
const requestLoginEpic = (action$) =>
action$
.ofType(REQUEST_LOGIN)
.mergeMap(({payload}) => login(payload.email, payload.password)
.concatMap(({response}) => [resolveLogin(response.content), loadAbout()])