I'm trying out the createAsyncThunk but can't get the extraReducers to fire. Here is what I have right now:
export const getAllAgents = createAsyncThunk(
"getAllAgents",
async (token: string) => {
let headers = new Headers();
headers.append("Authorization", `Bearer ${token}`);
headers.append("Content-Type", "application/json");
const response = await fetch(`${API.endpoint}/data/agent`, {
method: "get",
headers,
redirect: "follow",
});
const data = await response.json();
console.log("Response in thunk: ", { data });
return data;
}
);
export const agentSlice = createSlice({
name: "agentSlice",
initialState,
reducers: {},
extraReducers:
//builder call back required for typesafety
//https://redux-toolkit.js.org/usage/usage-with-typescript#type-safety-with-extrareducers
(builder) => {
console.log(createNewAgent.fulfilled);
builder.addCase(createNewAgent.fulfilled, (state, action) => {
console.log("fulfilled action", { action });
});
console.log(getAllAgents.fulfilled);
builder.addCase(getAllAgents.fulfilled, (state, action) => {
state.agents = action.payload.agents;
});
},
});
I also see the fulfilled action being called in the dev tools:
What is amiss?
I had the same problem. My mistake was that I was adding reducers outside of extraReducers.
This was wrong:
const authSlice = createSlice({
name: 'auth',
initialState,
extraReducers: {
[login.fulfilled]: (state, action) => {},
},
[signUp.fulfilled]: state => {}
}
Related
I'm trying to fetch a list from database and add to my state. but the action.payload is undefined on the api the result is correct.
mySlice
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import { fileFetch } from "./fileAPI";
const initialState = {
loading: "idle" | "pending" | "succeeded" | "failed",
error: false,
filesUploaded: null,
};
export const fetchFiles = createAsyncThunk("files/fetchFiles", () => {
return fileFetch();
});
export const fileSlice = createSlice({
name: "files",
initialState,
reducers: {},
extraReducers(builder) {
builder
.addCase(fetchFiles.pending, (state, action) => {
state.loading = "pending";
})
.addCase(fetchFiles.fulfilled, (state, action) => {
console.log(action);
state.loading = "succeeded";
state.filesUploaded = action.payload;
})
.addCase(fetchFiles.rejected, (state, action) => {
state.loading = "failed";
state.filesUploaded = [];
state.error = action.error.message;
});
},
});
export default fileSlice.reducer;
myAPI
const api = axios.create({
baseURL: "http://localhost:8081/file/",
headers: {
"content-type": "application/json",
},
});
export const fileFetch = async () => {
await api
.get("getAll")
.then((res) => {
console.log(res.data);
return res.data;
})
.catch((err) => {
throw new Error(err);
});
};
the console.log on the api is returning the correct data.
any idea why the payload is undefined?
thanks.
Might be because you are using both async-await and Promise methods in fileFetch function. Try updating it to this
export const fileFetch = async () => {
const response = await api.get("getAll")
return response.data
};
myApi
export const fileFetch = () => api.get("getAll")
mySlice
export const fetchFiles = createAsyncThunk(
"files/fetchFiles",
async ({ rejectWithValue }) => {
try {
const response = await fileFetch();
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
Also working lifecycle methods
I'm trying to achieve automated refetching without using RTK Query.
I.e. im writing my API calls using createAsyncThunk & Axios.
On create(post) or update(patch) request being successful, I would rather just "refetch" data, rather than push my changes into the original data set.
This is how it would be done with RTK Query:https://redux-toolkit.js.org/rtk-query/usage/automated-refetching
By invalidating the data.
A simple solution would be if I could call my "fetchClients" thunk..
Any ideas?
import { createSlice, createAsyncThunk, current } from "#reduxjs/toolkit/";
import axios from "axios";
import { getAxiosHeaders } from "../Api/apiHelper";
const initialState = {
clients: [],
client: null,
status: "idle", //'idle' | 'loading' | 'succeeded' | 'failed'
error: null,
isModalOpen: false,
};
export const fetchClients = createAsyncThunk("clients/fetchClients", async () => {
alert("hello fetch clients");
const response = await axios.get(CLIENTS_URL, { headers });
return response.data.clients;
});
export const addNewClient = createAsyncThunk("clients/addNewClient", async (body) => {
const response = await axios.post(CLIENTS_URL, body, { headers });
return response.data;
});
export const clientsSlice = createSlice({
name: "clients",
initialState,
reducers: {
toggleModal: (state, action) => {
state.isModalOpen = !action.payload;
},
},
},
extraReducers: (builder) => {
builder
.addCase(fetchClients.pending, (state, action) => {
state.status = "loading";
})
.addCase(fetchClients.fulfilled, (state, action) => {
state.status = "success";
state.clients = action.payload;
})
.addCase(fetchClients.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
})
.addCase(addNewClient.fulfilled, (state, action) => {
console.log(state.clients);
// REFETCH DATA i.e. fetchClients()
// state.clients.push(action.payload);
})
},
});
export const { clientAdded, toggleModal, setClient } = clientsSlice.actions;
export default clientsSlice.reducer;
res in then gets me an object but still can t update it redux state
i created account the when it returns me the value res .i can console it but i can t save it in the redux state
const initialState = {
user: {},
};
export const Auth_Slice = createSlice({
name: "auth",
initialState,
reducers: {
loginWithEmail: async (state, action) => {
await createUserWithEmailAndPassword(
auth,
action.payload.email,
action.payload.password
).then((res) => {
state.user = res;
console.log(res.user);
});
},
},
});
you need to create async actions and use extraReducers in create slice.
export const createUserWithEmailAndPassword = createAsyncThunk(
"createUserWithEmailAndPassword",
async (payload) => {
const response = await createUserWithEmailAndPassword(
auth,
payload.email,
payload.password
);
return response;
}
);
const initialState = {
status: "",
user: {},
};
export const Auth_Slice = createSlice({
name: "auth",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(createUserWithEmailAndPassword.pending, (state) => {
state.status = "loading";
})
.addCase(createUserWithEmailAndPassword.fulfilled, (state, action) => {
state.status = "idle";
state.user = action.payload?.user ?? {};
});
}
})
;
I try to use 'redux toolkit' to create async function for my React Native app. below are my createAsyncThunk function:
export const signin = createAsyncThunk(
"signin",
async (dispatch, getState) =>{
return await axios.post(localhost+'/api/user_auth/', {
email:'abc#example.com',
password:'password'
}).then(res=> console.log(res.data))
}
)
export const userSlice = createSlice({
name: 'user',
initialState: {
user:{},
status:null
},
extraReducers:{
[signin.pending]: (state, action)=>{
state.status = 'loading...'
},
[signin.fulfilled]: (state, action)=>{
state.status = 'success'
state.user = action.payload
},
[signin.rejected]: (state, action)=>{
state.status = 'failed'
},
},
reducers: {
},
})
when running the function everything seems to work, the console.log inside the then() will return the correct data. But when I log out the state.user I will get:
{"status": "success", "user": {}}
How should I return the response data?
If I want only the specific part of the response data like response.data, how can I filter that to return to reducer?
Update01
I just test this:
export const signin = createAsyncThunk(
"signin",
async (dispatch, getState) =>{
const res = await axios.post(localhost+'/api/user_auth/', {
email:'abc#example.com',
password:'password'
})
console.log( await res.data)
return await res.json()//<-- give status "failed"
}
)
And I when I logged state.user, I will get:
{"status": "failed", "user": {}}
It seems like the toolkit is very particular on the await format.
I am using react with redux tookit to call my api and store my response in the state, but whenever i am calling the async thunk i am getting undefined in response but i am log my response in api, i am getting the expected response, i didn't know as i am beginner in redux, can anybody please help me what i am doing wrong.
below is my memory slice reducer
import { RecentPublishedApi } from "../../components/api/api";
export const fetchMemoryAsync = createAsyncThunk(
"memory/recentPublishedApi",
async (obj) => {
const response =await RecentPublishedApi(obj);
console.log("i am inside the thunk",response)
return response;
}
);
const initialState = {
data: [],
status: "",
};
export const MemorySlice = createSlice({
name: "memory",
initialState,
reducers: {
},
extraReducers: {
[fetchMemoryAsync.pending]: (state) => {
state.status = "loading";
},
[fetchMemoryAsync.fulfilled]: (state, action) => {
console.log("fulfilled")
state.status = "idle";
console.log(action)
state.data=action.payload;
},
[fetchMemoryAsync.rejected]: (state, action) => {
state.status = "failed";
state.error = action.payload;
},
},
});
// export const { addData } = MemorySlice.actions;
export const selectData = (state) => state.memory.data;
export default MemorySlice.reducer;
my code sandbox link-
https://codesandbox.io/s/hidden-snowflake-px34f?file=/src/App.js
You are not returning anything from your RecentPublishedApi. Add a return statement.
Also, that Promise you build there is already a promise, no need to wrap that manually.
import axios from "axios";
export const RecentPublishedApi = async (data) => {
const headers = {
"Content-Type": "application/json",
"X-CSRF-TOKEN": "e7lwcn_OBGJuu2QsIA8auXzsvi9RGlzueRGDDwVsSKU"
};
return axios
.post("https://public.cuebackqa.com/api/timeline/list", data, {
headers: headers
})
};