DEV Community

Cover image for How to call APIs in React Redux ?
CyberWolves
CyberWolves

Posted on

How to call APIs in React Redux ?

Hi, Today we are going to build simple React application which call the get request and show the data. We are using Redux for this application, Redux is a state management library for javascript applications. If you are not familiar with Redux, I highly recommend you to read the Redux fundamentals from Redux documentation. For better understanding watch the demo video.

So let's start coding...

Demo Video

Source Code

Project Structure
react redux api
Create React App

$ npx create-react-app react-redux-api
$ cd react-redux-api
$ npm start
Enter fullscreen mode Exit fullscreen mode

Install Dependencies

Redux : It's a State management library for javascript applications.
Axios : It's a promise-based HTTP client that supports an easy-to-use API.
React-Redux : React Redux is the official React Ui bindings layer for Redux.
@reduxjs/toolkit : For writing clean redux code and it comes with most widly used Redux addons.

Create API Actions
src/store/api.js

import { createAction } from "@reduxjs/toolkit";

export const apiCallBegan = createAction("api/callBegan");
export const apiCallSucess = createAction("api/callSuccess");
export const apiCallFailed = createAction("api/callFailed");
Enter fullscreen mode Exit fullscreen mode

Create API Middleware
src/store/middleware/api.js

import axios from "axios";
import * as actions from "../api";

const api =
    ({ dispatch }) =>
    (next) =>
    async (action) => {
        if (action.type !== actions.apiCallBegan.type) return next(action);

        const { url, method, data, onStart, onSuccess, onError } =
            action.payload;

        if (onStart) dispatch({ type: onStart });

        next(action);

        try {
            const response = await axios.request({
                baseURL: "https://jsonplaceholder.typicode.com",
                url,
                method,
                data,
            });
            // General
            dispatch(actions.apiCallSucess(response.data));
            // Specific
            if (onSuccess)
                dispatch({ type: onSuccess, payload: response.data });
        } catch (error) {
            // General
            dispatch(actions.apiCallFailed(error.message));
            // Specific
            if (onError) dispatch({ type: onError, payload: error.message });
        }
    };

export default api;
Enter fullscreen mode Exit fullscreen mode

Redux already has an async middleware function called Redux "Thunk" middleware. The thunk middleware allows us to write functions that get dispatch and getState as arguments. For better understanding read documentation.

Create Actions & Reducers for Posts
src/store/posts.js

import { createSlice } from "@reduxjs/toolkit";
import { apiCallBegan } from "./api";

const slice = createSlice({
    name: "posts",
    initialState: {
        list: [],
        loading: false,
    },

    reducers: {
        postsRequested: (posts, action) => {
            posts.loading = true;
        },

        postsReceived: (posts, action) => {
            posts.list = action.payload;
            posts.loading = false;
        },

        postsRequestFailed: (posts, action) => {
            posts.loading = false;
        },
    },
});

export default slice.reducer;

const { postsRequested, postsReceived, postsRequestFailed } = slice.actions;

const url = "/posts";

export const loadposts = () => (dispatch) => {
    return dispatch(
        apiCallBegan({
            url,
            onStart: postsRequested.type,
            onSuccess: postsReceived.type,
            onError: postsRequestFailed.type,
        })
    );
};
Enter fullscreen mode Exit fullscreen mode

Configure Store

import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import reducer from "./posts";
import api from "./middleware/api";

export default function store() {
    return configureStore({
        reducer,
        middleware: [...getDefaultMiddleware(), api],
    });
}
Enter fullscreen mode Exit fullscreen mode

Posts Component
src/components/posts.js

import { useDispatch, useSelector } from "react-redux";
import { loadposts } from "../store/posts";
import { useEffect } from "react";

const Posts = () => {
    const dispatch = useDispatch();
    const posts = useSelector((state) => state.list);

    useEffect(() => {
        dispatch(loadposts());
    }, [dispatch]);

    return (
        <div>
            <h1>Posts</h1>
            <ul>
                {posts.map((post) => (
                    <li key={post.id}>{post.title}</li>
                ))}
            </ul>
        </div>
    );
};

export default Posts;
Enter fullscreen mode Exit fullscreen mode

App.js

import { Provider } from "react-redux";
import configureStore from "./store/configureStore";
import Posts from "./components/posts";
import "./App.css";

const store = configureStore();

const App = () => {
    return (
        <Provider store={store}>
            <Posts />
        </Provider>
    );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

That's it, run the project on your local server. check APIs are working or not. If you found any mistakes or making code better please let me know. I hope you have learned something.

If you like this post, support me on my youtube channel it inspire me a lot.

Thank You...

Top comments (3)

Collapse
 
wailh profile image
wailh

thank you for this article, I really appreciate it. Just a question, I wanna change the url endpoint. I'm using a restaurant menu app and I want the url to be changed every time a user click on a plate(eg: pizzas or burgers). I have a component that have the menu list.

Collapse
 
jeremymcn profile image
JeremyMcn

Hey, I dont seem to be getting any errors but it just comes up as a blank app in my browser.

I uploaded it in an image and in the configureStore.js the getDefaultMiddleware is crossed out not sure if this has anything to do with it but seems like the only thing not working.

Collapse
 
wexengos profile image
Giovane Nilmer O. S.

It was deprecated. Instead of importing it from "@reduxjs/toolkit" and setting it to the array like that, type your configureStore as:

return configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api),
})