Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux Toolkit and Axios

I'm using Redux Toolkit to connect to an API with Axios. I'm using the following code:

const products = createSlice({
    name: "products",
    initialState: {
        products[]
    },
    reducers: {
        reducer2: state => {
            axios
                .get('myurl')
                .then(response => {
                    //console.log(response.data.products);
                    state.products.concat(response.data.products);
            })

        }
    }
});

axios is connecting to the API because the commented line to print to the console is showing me the data. However, the state.products.concat(response.data.products); is throwing the following error:

TypeError: Cannot perform 'get' on a proxy that has been revoked

Is there any way to fix this problem?

like image 276
James Hameson Avatar asked Feb 14 '20 05:02

James Hameson


2 Answers

I would prefer to use createAsyncThunk for API Data with extraReducers

Let assume this page name is productSlice.js

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

export const fetchProducts = createAsyncThunk(
  "products/fetchProducts", async (_, thunkAPI) => {
     try {
        //const response = await fetch(`url`); //where you want to fetch data
        //Your Axios code part.
        const response = await axios.get(`url`);//where you want to fetch data
        return await response.json();
      } catch (error) {
         return thunkAPI.rejectWithValue({ error: error.message });
      }
});

const productsSlice = createSlice({
   name: "products",
   initialState: {
      products: [],
      loading: "idle",
      error: "",
   },
   reducers: {},
   extraReducers: (builder) => {
      builder.addCase(fetchProducts.pending, (state) => {
        state. products = [];
          state.loading = "loading";
      });
      builder.addCase(
         fetchProducts.fulfilled, (state, { payload }) => {
            state. products = payload;
            state.loading = "loaded";
      });
      builder.addCase(
        fetchProducts.rejected,(state, action) => {
            state.loading = "error";
            state.error = action.error.message;
      });
   }
});


export const selectProducts = createSelector(
  (state) => ({
     products: state.products,
     loading: state.products.loading,
  }), (state) =>  state
);
export default productsSlice;

In your store.js add productsSlice: productsSlice.reducer in out store reducer.

Then for using in component add those code ... I'm also prefer to use hook

import { useSelector, useDispatch } from "react-redux";

import {
  fetchProducts,
  selectProducts,
} from "path/productSlice.js";

Then Last part calling those method inside your competent like this

const dispatch = useDispatch();
const { products } = useSelector(selectProducts);
React.useEffect(() => {
   dispatch(fetchProducts());
}, [dispatch]); 

And Finally, you can access data as products in your component.

like image 56
SHUVO MUSA Avatar answered Oct 19 '22 10:10

SHUVO MUSA


It is happening because your reducer function is not a pure function, it should not be having any asynchronous calls.

something like this should work. it will fix the error you are getting

const products = createSlice({
    name: "products",
    initialState: {
        products: []
    },
    reducers: {
        reducer2: (state, { payload }) => {
                return { products: [...state.products, ...payload]}
         })

      }
    }
});

and api should be called outside

const fetchProducts = () => {

   axios.get('myurl')
     .then(response => {
        //console.log(response.data.products);
        store.dispatch(products.actions.reducer2(response.data.products))
   })
};

PS: haven't tried running above code, you may have to make modifications as per your need.

like image 9
Kishan Rajdev Avatar answered Oct 19 '22 09:10

Kishan Rajdev