How to call RTK mutations after first finishes - redux

I am using REDUX-TOOLKIT-QUERY, Now I have a situation, I have to call one mutation. once that mutation returns a response, and I have to use that response in the other three mutations as a request parameter. How can we implement this in a proper way?
const [getSettings, { isLoading, data: Settings }] =useSettingsMutation();
const [getMenu] =useMenuMutation();
const [getServices] = useServicesMutation();
useEffect(() => {
const obj = {
Name: "someNme",
};
if (obj) getSettings(obj);
if (Settings?._id ) {
const id = settings._id;
getServices(id);
getMenu(id);
getServices(id);
}
}, []);

useMutation will return a promise, you can directly await this promise to get the return result:
const [getSettings, { isLoading, data: Settings }] = useSettingsMutation()
const [getMenu] = useMenuMutation()
const [getServices] = useServicesMutation()
useEffect(() => {
;(async () => {
try {
const obj = {
Name: 'someNme',
}
const data = await getSettings(obj).unwrap()
if (data._id !== undefined) {
const id = data._id
getServices(id)
getMenu(id)
getServices(id)
// ...
}
} catch (err) {
// ...
}
})()
}, [])

Related

Unexpected mutation in pinia prop when change local component reactive()

When the value of an reactive object is changed, a prop in my Pinia store is mutated. I tried different ways of attributing new value to this store to avoid this problem, but so far I dont't really understand what is happenning. This is my code:
Component
const form = reactive({
name: "",
exercises: [{ exercise: "", method: "", series: "" }],
});
const handleChange = ({ value, name }: any, eventIndex: any) => {
const newEx = form.exercises.map((ex, index) => ({
...ex,
...(index === eventIndex ? { [name]: value } : null),
}));
const newForm = { name: form.name, exercises: newEx };
Object.assign(form, newForm)
};
const onSubmit = async () => {
const { valid } = await formRef.value.validate();
if (!valid) return;
const storeTraining = workoutStore.newWorkout.training || [];
const workout = {
...workoutStore.newWorkout,
training: [...storeTraining, form],
};
workoutStore.setNewWorkout(workout);
isOpen.value = false;
};
Store
import { ref, computed } from "vue";
import { defineStore } from "pinia";
import type { IUser } from "#/domain/users/type";
import type { ITraining, IWorkout } from "#/domain/workouts/types";
export const useWorkoutStore = defineStore("workouts", () => {
const creatingWorkoutStudent = ref<IUser | null>(null);
const newWorkout = ref<Partial<IWorkout>>({});
const setCreatingWorkoutStudent = (newUser: IUser) => {
creatingWorkoutStudent.value = newUser;
};
const setNewWorkout = (workout: Partial<IWorkout>) => {
newWorkout.value = { ...workout };
return newWorkout.value;
};
const addNewTraining = (training: ITraining) => {
newWorkout.value.training
? newWorkout.value.training.push(training)
: (newWorkout.value.training = [training]);
};
const reset = () => {
newWorkout.value = {};
creatingWorkoutStudent.value = null;
};
return {
creatingWorkoutStudent,
setCreatingWorkoutStudent,
newWorkout,
setNewWorkout,
reset,
addNewTraining,
};
});
And this is a example of an input that mutates reactive values
<text-field
label="ExercĂ­cio"
#input="
handleChange(
{ value: $event.target.value, name: 'exercise' },
index
)
"
:value="exercise.exercise"
:rules="[validationRules.required]"
/>
Every time that a input changes a value in const form = reactive(), the same property in Pinia store is changed too.
I've created a fiddle to exemplify my issue here

I cannot understand WHY I cannot change state in Redux slice

I get the array of objects coming from backend, I get it with socket.io-client. Here we go!
//App.js
import Tickers from "./Components/TickersBoard";
import { actions as tickerActions } from "./slices/tickersSlice.js";
const socket = io.connect("http://localhost:4000");
function App() {
const dispatch = useDispatch();
useEffect(() => {
socket.on("connect", () => {
socket.emit("start");
socket.on("ticker", (quotes) => {
dispatch(tickerActions.setTickers(quotes));
});
});
}, [dispatch]);
After dispatching this array goes to Action called setTickers in the slice.
//slice.js
const tickersAdapter = createEntityAdapter();
const initialState = tickersAdapter.getInitialState();
const tickersSlice = createSlice({
name: "tickers",
initialState,
reducers: {
setTickers(state, { payload }) {
payload.forEach((ticker) => {
const tickerName = ticker.ticker;
const {
price,
exchange,
change,
change_percent,
dividend,
yeild,
last_trade_time,
} = ticker;
state.ids.push(tickerName);
const setStatus = () => {
if (ticker.yeild > state.entities[tickerName].yeild) {
return "rising";
} else if (ticker.yeild < state.entities[tickerName].yeild) {
return "falling";
} else return "noChange";
};
state.entities[tickerName] = {
status: setStatus(),
price,
exchange,
change,
change_percent,
dividend,
yeild,
last_trade_time,
};
return state;
});
return state;
},
},
});
But the state doesn't change. I tried to log state at the beginning, it's empty. After that I tried to log payload - it's ok, information is coming to action. I tried even to do so:
setTickers(state, { payload }) {
state = "debag";
console.log(state);
and I get such a stack of logs in console:
debug
debug
debug
3 debug
2 debug
and so on.

Solution to prefetch in a component on nextjs

I'm looking for a solution/module where I don't need to inject inital/fallback data for swr/react-query things from getServerSideProps. Like...
from
// fetcher.ts
export default fetcher = async (url: string) => {
return await fetch(url)
.then(res => res.json())
}
// getUserData.ts
export default function getUserData() {
return fetcher('/api')
}
// index.tsx
const Page = (props: {
// I know this typing doesn't work, only to deliver my intention
userData: Awaited<ReturnType<typeof getServerSideProps>>['props']
}) => {
const { data } = useSWR('/api', fetcher, {
fallbackData: props.userData,
})
// ...SSR with data...
}
export const getServerSideProps = async (ctx: ...) => {
const userData = await getUserData()
return {
props: {
userData,
},
}
}
to
// useUserData.ts
const fetcher = async (url: string) => {
return await fetch(url)
.then(res => res.json())
};
const url = '/api';
function useUserData() {
let fallbackData: Awaited<ReturnType<typeof fetcher>>;
if (typeof window === 'undefined') {
fallbackData = await fetcher(url);
}
const data = useSWR(
url,
fetcher,
{
fallbackData: fallbackData!,
}
);
return data;
}
// index.tsx
const Page = () => {
const data = useUserData()
// ...SSR with data...
}
My goal is making things related to userData modularized into a component.

Dispatch in Redux ToolKit not Changing state

I am trying to pass data to my redux store with the help of redux toolkit, but I'm unable to do so. I double checked that there is no problem with my data. Here is my code:
//USER DETAILS
export const userDetailsSlice = createSlice({
name: 'userDetails',
initialState: { loading: 'idle', user: {} },
reducers: {
userDetailsLoading(state) {
if (state.loading === 'idle') {
state.loading = 'pending';
}
},
userDetailsReceived(state, action) {
if (state.loading === 'pending') {
state.loading = 'idle';
state.user = action.payload;
}
},
userDetailsError(state, action) {
if (state.loading === 'pending') {
state.loading = 'idle';
state.error = action.payload;
}
},
},
});
export const {
userDetailsLoading,
userDetailsReceived,
userDetailsError,
} = userDetailsSlice.actions;
export const getUserDetails = (id) => async (dispatch, getState) => {
dispatch(userRegisterLoading());
try {
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.get(`/api/users/${id}`, config);
console.log(data);
dispatch(userDetailsReceived(data));
} catch (error) {
dispatch(userDetailsError(error.toString()));
}
};
I console logged my data right before the dispatch action: so the data is definitely there. Therefore I think there's something wrong with my code. Here is my code for my redux store:
import { configureStore } from '#reduxjs/toolkit';
import { photoListSlice, photoCreateSlice } from './photo';
import { userRegisterSlice, userLoginSlice, userDetailsSlice } from './user';
const reducer = {
userRegister: userRegisterSlice.reducer,
userLogin: userLoginSlice.reducer,
userDetails: userDetailsSlice.reducer,
};
const store = configureStore({ reducer });
export default store;
As seen from this photo: the action userDetailsReceived was called but the state for user did not change.
Any help or hint would be greatly appreciated!!
I made a typo on the first dispatch call of getUserDetails function, I dispatched userRegisterLoading instead of userDetailsLoading... Now it works fine after the change.
export const getUserDetails = (id) => async (dispatch, getState) => {
dispatch(userDetailsLoading());
try {
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.get(`/api/users/${id}`, config);
console.log(data);
dispatch(userDetailsReceived(data));
} catch (error) {
dispatch(userDetailsError(error.toString()));
}
};

useEffect infinite loop with dependency array on redux dispatch

Running into an infinite loop when I try to dispatch an action which grabs all recent posts from state.
I have tried the following in useEffect dependency array
Object.values(statePosts)
useDeepCompare(statePosts)
passing dispatch
omitting dispatch
omitting statePosts
passing statePosts
doing the same thing in useCallback
a lot of the suggestions came from here
I have verified that data correctly updates in my redux store.
I have no idea why this is still happening
my component
const dispatch = useDispatch()
const { user } = useSelector((state) => state.user)
const { logs: statePosts } = useSelector((state) => state.actionPosts)
const useDeepCompare = (value) => {
const ref = useRef()
if (!_.isEqual(ref.current, value)) {
ref.current = value
}
return ref.current
}
useEffect(() => {
dispatch(getActionLogsRest(user.email))
}, [user, dispatch, useDeepCompare(stateLogs)])
actionPosts createSlice
const slice = createSlice({
name: 'actionPosts',
initialState: {
posts: [],
},
reducers: {
postsLoading: (state, { payload }) => {
if (state.loading === 'idle') {
state.loading = 'pending'
}
},
postsReceived: (state, { payload }) => {
state.posts = payload
},
},
})
export default slice.reducer
const { postsReceived, postsLoading } = slice.actions
export const getActionPostsRest = (email) => async (dispatch) => {
try {
dispatch(postsLoading())
const { data } = await getUserActionPostsByUser({ email })
dispatch(postsReceived(data.userActionPostsByUser))
return data.userActionPostsByUser
} catch (error) {
throw new Error(error.message)
}
}
Remove dispatch from dependencies.
useEffect(() => {
dispatch(getActionLogsRest(user.email))
}, [user, dispatch, useDeepCompare(stateLogs)])
you cannot use hook as dependency and by the way, ref.current, is always undefined here
const useDeepCompare = (value) => {
const ref = useRef()
if (!_.isEqual(ref.current, value)) {
ref.current = value
}
return ref.current
}
because useDeepCompare essentially is just a function that you initiate (together with ref) on each call, all it does is just returns value. That's where the loop starts.

Resources