Hi i have a problem with createAsyncThunk, i have started a json-server with json document in it.
i'm tryng to dispatch the action getTodos but the action is always rejected and i do not why.
i'm sure the server is working properly because i testes it with postman, any one can help me?
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import { filterTodo } from "./FilterSlice";
// the url are deleted for privacy
const urlTodos = "";
const urlFilter = "";
export const getTodos = createAsyncThunk(
"todos/getTodos",
async (data = null, thunkAPI) => {
const todosPromise = fetch(urlTodos)
.then((resp) => resp.json())
.then((res) => res);
console.log("todoPromise", typeof todosPromise);
const filterPromise = fetch(urlFilter)
.then((resp) => resp.json())
.then((res) => res);
let [todos, activeFilter] = await Promise.all([
todosPromise,
filterPromise,
]);
thunkAPI.dispatch(filterTodo(activeFilter));
return todos;
}
);
export const todosSlice = createSlice({
name: "todos", // nome della slice
initialState: [],
reducers: {
addTodo(state, action) {
console.log("add todo");
state.push(action.payload);
},
removeTodo(state, action) {
state = state.filter((todo) => todo.name !== action.payload.name);
return state;
},
toggleTodo(state, action) {
state = state.map(function (todo) {
if (todo.id === action.payload.id) {
todo.completed = !todo.completed;
}
});
},
},
extraReducers: (builder) => {
// reducer che gestisce la pending action
builder
.addCase(getTodos.pending, (state, actions) => {
state.status = "loading";
console.log("in pending");
})
.addCase(getTodos.fulfilled, (state, action) => {
state.status = "success";
console.log("in getTodos fulfilled", action.payload);
state = action.payload;
return state;
})
.addCase(getTodos.rejected, (state, action) => {
console.log("in getTodos rejected", action.payload);
});
},
});
const { actions, reducer } = todosSlice;
export const { addTodo, removeTodo, toggleTodo } = actions;
export default reducer;
it was dispatched in the following way
const dispatch = useDispatch();
useEffect(() => {
console.log("dentro use effect");
dispatch(getTodos());
return () => {};
}, [dispatch]);
and the structure of the json object is the following
{
"todos": [
{
"completed": true,
"name": "Call my mum",
"dueDate": "17/3/2022",
"user_id": 1,
"id": 1
},
{
"completed": false,
"name": "go to school",
"dueDate": "17/3/2022",
"user_id": 2,
"id": 2
},
{
"completed": true,
"name": "do homework",
"dueDate": "17/3/2022",
"user_id": 3,
"id": 3
}
],
"filter": ["ALL"]
}
this is what appen when i try to excute the program
the console is that
the redux extension of chrome reports this error
i found the error:
extraReducers: (builder) => {
builder
.addCase(getTodos.pending, (state, actions) => {
console.log("in pending");
})
.addCase(getTodos.fulfilled, (state, action) => {
console.log("in getTodos fulfilled", action.payload);
state = action.payload;
return state;
})
.addCase(getTodos.rejected, (state, action) => {
console.log("in getTodos rejected", action.payload);
});
},
});
i removed the state.status = string and now it works
Related
I tried this but did not help me. this is my slice:
export const getAll = () => {
return axios.get('http://localhost:4000/students').then(response => {
return response.data
})
}
export const retriveStudents = createAsyncThunk(
"students/retrive", async () => {
return await getAll()
}
)
const studentSlice = createSlice({
name: "student",
initialState,
reducers: {
addNote: (state, action) => {
return { ...state, note: action.payload }
}
},
extraReducers: {
[retriveStudents.fulfilled]: (state, action) => {
studentSlice.actions.addNote("MY DATA...")
return { ...state, items: [...action.payload] }
}
}
})
In extraReducers I want to dispatch addNote action.
I tried the following, but does not work.
extraReducers: {
[retriveStudents.fulfilled]: (state, action) => {
studentSlice.actions.addNote("MY DATA...") // this. line ...
return { ...state, items: [...action.payload] }
}
}
IMAGE LINK HERE. it doubles the initial return.
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit'
import axios from 'axios'
let url = 'http://localhost:3000/api/v1/posts'
const initialState = {
allPosts: [],
isLoading: false,
isError: false,
}
export const getAllPost = createAsyncThunk('allPosts/getAllPost', async (page, thunkAPI) => {
console.log(page)
try {
const { data } = await axios.get(`${url}?page=${page}`)
return data.posts
} catch (error) {
console.log(error)
}
})
const allPostSlice = createSlice({
name: 'allPosts',
initialState,
reducers: {},
extraReducers: {
[getAllPost.pending]: (state) => {
state.isLoading = true
},
[getAllPost.fulfilled]: (state, { payload }) => {
console.log(payload)
state.allPosts = [...state.allPosts, ...payload]
state.isLoading = false
},
[getAllPost.rejected]: (state) => {
state.isLoading = false
state.isError = true
},
},
})
export default allPostSlice.reducer
When I try to append ...state.allPosts, which is supposed to be the old state, it prints double the initial payload. I only need it printed once, not twice.
[getAllPost.fulfilled]: (state, { payload }) => {
console.log(payload)
state.allPosts = [...state.allPosts, ...payload]
state.isLoading = false
},
How can I print my payload only once using state.allPosts?
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;
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.