Samke11
Samke11

Reputation: 525

Redux - API is being called multiple times (Redux Thunk)

I am using Next.js and Redux as a state management. Everything is working perfectly fine except one thing and that is API calls. What I mean by this is that API is being called multiple times even though I dispatched it just once. When I go and see in the network tab in Google Chrome, I see multiple calls being called.

I am also using Redux Thunk and Redux Toolkit:

store

import { configureStore } from "@reduxjs/toolkit";
import layoutSlice from "./layoutSlice";
export const store = configureStore({
  reducer: {
    layout: layoutSlice,
  },
});

layoutSlice

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

const BASE_URL = "http://localhost:1337";

export const getHeaderData = createAsyncThunk(
  "layout/getHeaderData",
  async () => {
    const response = await axios.get(
      `${BASE_URL}/api/navigations?populate=*&sort=id`
    );
    return response.data;
  }
);

export const getFooterData = createAsyncThunk(
  "layout/getFooterData",
  async () => {
    const response = await axios.get(
      `${BASE_URL}/api/footers?populate[ContactForm][populate]=*&populate[Links][populate]=*&populate[Info][populate]=*`
    );
    return response.data;
  }
);

const initialState = {
  header: [],
  footer: [],
  isLoadingHeader: false,
  isLoadingFooter: false,
};

const layoutSlice = createSlice({
  name: "layout",
  initialState,
  extraReducers: {
    [getHeaderData.pending]: (state) => {
      state.isLoadingHeader = true;
    },
    [getHeaderData.fulfilled]: (state, action) => {
      state.header = action.payload;
      state.isLoadingHeader = false;
    },
    [getHeaderData.rejected]: (state) => {
      state.isLoadingHeader = false;
    },
    [getFooterData.pending]: (state) => {
      state.isLoadingFooter = true;
    },
    [getFooterData.fulfilled]: (state, action) => {
      state.footer = action.payload;
      state.isLoadingFooter = false;
    },
    [getFooterData.rejected]: (state) => {
      state.isLoadingFooter = false;
    },
  },
});

export default layoutSlice.reducer;

generalLayout (where the API is called)

import React, { useEffect, useState } from "react";
import { Header, Footer } from "../components";
import { useDispatch, useSelector } from "react-redux";
import { getHeaderData, getFooterData } from "../redux/layoutSlice";

const GeneralLayout = ({ children }) => {
  const { isLoadingHeader, isLoadingFooter } = useSelector(
    (state) => state.layout
  );
  const dispatch = useDispatch();

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

  if (isLoadingHeader === true || isLoadingFooter === true) {
    return <div>Loading...</div>;
  }

  return (
    <>
      <Header />
      {children}
      <Footer />
    </>
  );
};

export default GeneralLayout;

I am also using Strapi (dont mind the query for the API call, it works for me so I do not think the problem is there, at least it should not be)

Network tab

enter image description here

Upvotes: 2

Views: 4822

Answers (3)

Prakash Kumawat
Prakash Kumawat

Reputation: 1

It happens because of react strict mode. React strict mode will render the UI twice so it's sending all request twice. If you want to disable it, you can do it from next.config.js by setting reactStrictMode: false. This will be automatically disable it in production mode.

Upvotes: 0

user18821127
user18821127

Reputation: 366

It is because of useEffect In development, React strictmode calls all effects twice to catch any memory leaks and other issues.

This only applies to development mode, production behavior is unchanged So you don't want to worry about it being called twice in production/build

From official React docs (beta at time of writing)

If your Effect fetches something, the cleanup function should either abort the fetch or ignore its result:

useEffect(() => {
  let ignore = false;

  async function startFetching() {
    const json = await fetchTodos(userId);
    if (!ignore) {
      setTodos(json);
    }
  }

  startFetching();

  return () => {
    ignore = true;
  };
}, [userId]);

Read more here

Upvotes: 4

Abubakar Hmd
Abubakar Hmd

Reputation: 1

You must add a dispatch to dependency of useEffect function.. make sure the peomise function receives parameter as the informations you want to get or post.. And call the parameter inside axios func after APIurl.

Upvotes: 0

Related Questions