Fetching data with “createAsyncThunk" from RTK(Redux toolkit)
Ever wondered how to fetch async data in RTK. As we all know RTK saves us a lot of time writing immutable code in redux. So let’s fetch async data with createAsyncThunk.
Enough words about redux right? Let’s understand createAsyncThunk.
createAsyncThunk takes three parameters : a string action
type
value, apayloadCreator
callback, and anoptions
object. For example, atype
argument of'users/requestStatus'
will generate these action types:
pending
:'users/requestStatus/pending'
fulfilled
:'users/requestStatus/fulfilled'
rejected
:'users/requestStatus/rejected'
payloadCreator:
A callback function that should return a promise containing the result of some asynchronous logic. It may also return a value synchronously. If there is an error, it should either return a rejected promise containing an Error
instance or a plain value such as a descriptive error message or otherwise a resolved promise with a RejectWithValue
argument as returned by the thunkAPI.rejectWithValue
function.
Options
An object with the following optional fields:
condition
: a callback that can be used to skip execution of the payload creator and all action dispatches, if desired. See Canceling Before Execution for a complete description.dispatchConditionRejection
: ifcondition()
returnsfalse
, the default behavior is that no actions will be dispatched at all. If you still want a "rejected" action to be dispatched when the thunk was canceled, set this flag totrue
.
Return Value
createAsyncThunk
returns a standard Redux thunk action creator. The thunk action creator function will have plain action creators for the pending
, fulfilled
, and rejected
cases attached as nested fields.
Enough talking right ? Let’s right some code
//postsSlice.js
import { createSlice, createAsyncThunk } from “@reduxjs/toolkit”;
export const getUsers = createAsyncThunk(“posts/getUsers”, () => {
return fetch(“https://jsonplaceholder.typicode.com/posts")
.then((response) => {
if (!response.ok) throw Error(response.statusText);
return response.json();
})
.then((json) => json);
});
export const postsSlice = createSlice({
name: “posts”,
initialState: {
loading: false,
hasErrors: “ “,
posts: [],
},
extraReducers: {
[getUsers.pending]: (state) => {
state.loading = true;
},
[getUsers.rejected]: (state, action) => {
state.loading = false;
state.hasErrors = action.error.message;
},
[getUsers.fulfilled]: (state, { payload }) => {
state.posts = payload;
state.loading = false;
},
},
});
//export const postsSelector = (state) => state.posts;
const appReducer = postsSlice.reducer;
export default appReducer;
Let me break the code for you as I explained above how it takes three parameters so the first string type parameter is our posts/getUsers since I’m fetching posts I just wrote it this way it. getUsers is the function I’m using here and posts happens to be my slice name so it becomes posts/getUsers. It can be written however you want.
createAsyncThunk being a standard redux action creator will have plain action creators for the pending
, fulfilled
, and rejected
cases attached as nested fields. so we have [getUsers.pending], [getUsers.rejected] and [getUsers.fulfilled] . Since it takes a payloadCreator , To get the error message from the reject Promise you’ll access action.error.message
.
To get instead the API’s payload you’ll access action.payload
.
If you need to access thunk’s parameters to use dispatch
or getState
, pass the thunkAPI
parameter to the callback function (or destructure what you need):
eg) const getUsers = createAsyncThunk("users/getUsers", (thunkAPI) => {...//do something async}
or const getUsers = createAsyncThunk("users/getUsers", (args) => {...//do something async}
I think it’s time not to bore you and show you the code (assummed you knew all about creating & using slices in RTK). Let’s create our store next
//store.js
import { configureStore } from “@reduxjs/toolkit”;
import appReducer from “../features/appSlice”;
const store = configureStore({
reducer: {
posts: appReducer,
},
});
export default store;
//console.log(store.getState())
Next we’ll create Post.js to render our posts.
//Post.js
import React from “react”;
export const Post = ({ post }) => (
<article className=”post-excerpt”>
<h2>{post.title}</h2>
<p>{post.body.substring(0, 100)}</p>
</article>
);
export default Post;
Here comes the App.js file.
//App.js
import React, { useEffect } from “react”;
import { useDispatch, useSelector } from “react-redux”;
import { getUsers, postsSelector } from “./features/appSlice”;
import Post from “./Post”;
function App() {
const dispatch = useDispatch();
//const { posts, loading, error } = useSelector(postsSelector);
const { posts, loading, error } = useSelector(state=>state.posts);
useEffect(() => {
dispatch(getUsers());
}, [dispatch]);
const renderPosts = () => {
if (loading) return <p>Loading posts…</p>;
if (error) return <p>Unable to display posts.</p>;
return posts.map((post) => <Post key={post.id} post={post} excerpt />);
};
return <div>{renderPosts()}</div>;
}
export default App;
And lastly index.js.
I hope you have that created :). so that’s it guys I hope you enjoyed the way I enjoyed writing it.( This happened to be my first medium post).
feel free to ask me if in doubt .
https://twitter.com/carefree_ladka
Happy coding :)