notoriousRorious
notoriousRorious

Reputation: 134

React-Redux, dispatch is not adding my data to the state

Quite new to redux and just using it in this project for practice.

The data is successfully retrieved from the API call, and saved to 'data' (console logged on line 27). However, the console log of line 28 shows an empty array. Does anyone have any idea why this is?

AnimeList.js:

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';

import { useGetTrendingAnimeListQuery } from '../../services/animeApi';
import { addData } from './AnimeListSlice';

import AnimeCard from '../AnimeCard/AnimeCard';
import AnimeSelector from '../AnimeSelector/AnimeSelector';

import { Spin } from 'antd';

import './AnimeList.css';

const AnimeList = () => {

  const AnimeList = useSelector((state) => state.AnimeList.data);
  const dispatch = useDispatch();
  
  const { data, isFetching } = useGetTrendingAnimeListQuery();

  useEffect(() => {
    if (!isFetching) {
      dispatch(addData(data));
    }
  }, []);

  console.log(data);
  console.log(AnimeList);

  const loadingCards = [1, 2, 3, 4, 5];

  return (
    <div className='container'>
      {!isFetching
        ? <div className="wrapper">
            <AnimeSelector />
            <div className='anime-list-wrapper'>
              {AnimeList.map((anime) => (
                <AnimeCard anime={anime} key={anime.id} />
              ))}
            </div>
          </div>
        :
        <div className='wrapper'>
          <div className='anime-list-wrapper'>
            {loadingCards.map(() => (
              <div className='loading-card'>
                <Spin />
              </div>
            ))}
          </div>
        </div>
      }
    </div>
  )
}

export default AnimeList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

AnimeListSlice.js:

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

const initialState = {
    data: []
};

export const AnimeListSlice = createSlice({
    name: 'AnimeList',
    initialState,
    reducers: {
        addData: (state, action) => {
            state.data = action.payload;
        },
    }
});

export const { addData } = AnimeListSlice.actions;

export default AnimeListSlice.reducer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

animeApi.js:

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

const animeApiHeaders = {
    "Accept": "application/vnd.api+json",
    "Content-Type": "application/vnd.api+json",
};

const baseUrl = 'https://kitsu.io/api/edge';

const createRequest = (url) => ({ url, headers: animeApiHeaders });

export const animeApi = createApi({
    reducerPath: 'animeApi',
    baseQuery: fetchBaseQuery({ baseUrl }),
    endpoints: (builder) => ({
        getTrendingAnimeList: builder.query({
            query: () => createRequest('/trending/anime?limit=20'),
        }),
        getAllAnimeList: builder.query({
            query: () => createRequest('/anime?limit=20'),
        }),
    })
});

export const { useGetTrendingAnimeListQuery, useGetAllAnimeList } = animeApi;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Upvotes: 0

Views: 826

Answers (2)

Levon Ghazaryan
Levon Ghazaryan

Reputation: 109

It's because you are using (data and isFetching) variables inside of memoized function which doesn't have proper dependency of thous variables. If you want to make it work you must provide those variables as a dependency for useEffect function then it will work as expected.

Upvotes: 1

adsy
adsy

Reputation: 11532

You are trying to use an effect to set the data back up into redux via dispatch.

  useEffect(() => {
    if (!isFetching) {
      dispatch(addData(data));
    }
  }, []);

This wont work because this effect runs on mount and at mount time, the network request is still in flight and so the data has not come back yet.

Probably you want:

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

So that when data changes (e.g. when its returned from network), it will dispatch that new object.

Upvotes: 2

Related Questions