redux-observable How to dispatch multiple actions with pipe? - redux

I realized that
const pingEpic = action$ =>
action$.ofType('PING')
.delay(1000) // Asynchronously wait 1000ms then continue
.mapTo({ type: 'PONG' });
mean
dispatch({ type: 'PING' });
dispatch({ type: 'PONG' });
Howeber, I don't realize how to dispatch two actions with pipe.
my code is below
const signUpEpic = (action$: Observable<Action>) => action$.pipe(
ofType(actions.GET_DEVICE_TOKEN),
ofType(actions.SIGN_UP),
exhaustMap(({ payload }) => request({
url: 'users',
method: 'post',
data: {
user: {
email: payload.email,
password: payload.password,
device_token: payload.device_token,
sign_up_with: 'email_and_password',
},
},
}).pipe(
map(data => camelcaseKeysDeep(data)),
map(({ user, authToken }) => currentUserActions.successLogin({ user, authToken })),
catchError((errorMessage: string) => Observable.of(actions.failLogin({ errorMessage }))),
)),
);
Do you have any idea?
I tried below code too.
ofType(actions.GET_DEVICE_TOKEN),
mapTo(actions.SIGN_UP),
thanks

You can use mergeMap to dispatch multiple actions
.pipe(
mergeMap(data => [
camelcaseKeysDeep(data)),
currentUserActions.successLogin(data.user, data.authToken))
],
catchError((errorMessage: string) => Observable.of(actions.failLogin({ errorMessage }))),
)),

Related

How to set error in Redux toolkit array if no data returned from API

i started implementing RTK QUERYnow i am facing one issue , i have an API,the API returns user Settings. Now from API if the there is data related to user it returns success=1 otherwise success=0 , but in both cases it returns response status 200. Now i want to show error to user if sucess=0 and set the set the error in the RTk Error object. How can i implement that.
import { apiSlice } from "../../services/ApiSlice";
import * as URL from "../Urls";
export const userSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUserSettings: builder.mutation({
query: (body) => ({
url: URL.GET_SETTINGS,
method: "POST",
body: body,
responseHandler: (response) => response.json(),
validateStatus: (response, result) =>
response.status === 200 ? result : "error in fetching data",
}),
transformResponse: (response) => {
console.log({ response });
if (response.success === 0) return "Error in fetching data";
},
providesTags: (result, error, arg) => {
if (result) {
console.log(result);
return [...result.ids.map((id) => ({ type: "users", id })), "users"];
} else return ["users"];
},
}),
}),
});
export const { useGetUserSettingMutation } = userSlice;

Firebase Dispatch Error Object { "error": "Invalid claim 'kid' in auth header: 'tB0M2A' with iat: '1659290899'", }

I am trying to develop a react-native-app but everything was good. Once I have changed the authentication rules in firebase real time database. From that time, I am not able to POST/GET any request from firebase. I am storing the idToken which is returned after a user sign in the application in redux store.
case actionTypes.AUTHENTICATE_USER:
return {
...state,
isAuth: true,
token: action.payload
}
export const authUser = token => {
return {
type: actionTypes.AUTHENTICATE_USER,
payload: token
}}
The Login action code is as follows:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, returnSecuretoken: true
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})}
And I get the error while running the following code:
export const addPlace = place => (dispatch, getState) => {
let token = getState().token;
console.log("Add place Token:", token);
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`, {
method: "POST", body: JSON.stringify(place)
})
.catch(error => console.log(error))
.then(response => response.json())
.then(data => console.log("Dispatch Error", data))}
export const loadPlaces = () => (dispatch, getState) => {
let token = getState().token;
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`)
.catch(err => {
alert("Something Went Wrong, Sorry!");
console.log(err);
})
.then(res => res.json())
.then(data => {
const places = [];
for (let key in data) {
places.push({
...data[key],
key: key
})
}
dispatch(setPlaces(places));
})}
My firebase rule is as follows as I am still in initial phase:
{"rules": {
".read": "auth!=null" , // 2022-8-4
".write": "auth!=null", // 2022-8-4
}}
I am not getting any way to solve this. Please help.
Solved. The problem was with the returnSecureToken:true. I wrote returnSecuretoken which was creating the error. It will be:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, ***returnSecureToken: true***
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})
}

RTK Query: undefined extraOptions inside prepareHeaders

I set extraOptions in my endpoint like so :
const myApi = api.injectEndpoints({
endpoints: builder => ({
changePassowrd: builder.mutation({
query: (data) => ({
url: `${Config.BASE_URL}/users/${data.userId}`,
method: 'PATCH',
body: data,
}),
extraOptions: () => ({
myOption: 'Test Option',
}),
}),
})
})
And I try to read extraOptions in prepareHeaders like so:
const baseQuery = fetchBaseQuery({
baseUrl: Config.BASE_URL,
prepareHeaders: (headers, {getState, extra}) => {
console.log('Extra Stuff', extra); // undefined
return headers;
},
});
But I'm always getting undefined in the console after triggering the mutation, why is that? Am I using it wrong?
That's redux-thunk's extra, not the endpoint's extraOptions. It seems like fetchBaseQuery generally does not make use of extraOption - a pull request integrating that where necessary is highly welcome.

Why redux-thunk instead of store.dispatch/store.getState()

I've always used redux-thunk or some sort of middleware that grants me access to dispatch/getState, but I have a question that keeps bugging me. Why using that when we can import our store and call store.dispatch()/store.getState().
Later edit:
As a quick example, here's the original code:
function loadData(userId) {
return dispatch => fetch(`http://data.com/${userId}`) // Redux Thunk handles these
.then(res => res.json())
.then(
data => dispatch({ type: 'LOAD_DATA_SUCCESS', data }),
err => dispatch({ type: 'LOAD_DATA_FAILURE', err })
);
}
Basically, what I'm asking is why is it bad to rewrite this as:
import store from 'our-store';
function loadData(userId) {
return fetch(`http://data.com/${userId}`)
.then(res => res.json())
.then(
data => store.dispatch({ type: 'LOAD_DATA_SUCCESS', data }),
err => store.dispatch({ type: 'LOAD_DATA_FAILURE', err })
);
}

Redux wont update state when action is processed

My application is calling the action correctly as redux shows it gets the expected data it needs. The problem is it never stores the payload from the action. it is similar to my profile reducer and that works great.
This is the action
export const getCurrentFriends = () => dispatch => {
axios
.get("/api/friends")
.then(res =>
dispatch({
type: GET_FRIENDS,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: {}
})
);
};
This is the reducer
export default function(state = [], action) {
switch (action.type) {
case GET_FRIENDS:
return [
...state,
{
friends: action.payload
}
];
default:
return state;
}
}

Resources