1

When I first open the app it gets the data from api but when I refresh the page it says Cannot read properties of undefined (reading 'memes'). When I console.log the store item It shows an empty object but I can see the api with Redux Devtools extension. I got stuck with this problem and can't figure it out for two days.

slice.js

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

export const fetchJson = createAsyncThunk(
  "json/fetchJson",
  async () => {
    const data = await fetch("https://api.imgflip.com/get_memes");
    const json = await data.json();
    return json;
  }
);


export const loadJsonSlice = createSlice({
  name: "loadJson",
  initialState: {
    isLoading: false,
    hasError: false,
    memes:{}
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchJson.pending, (state) => {
        state.isLoading = true;
        state.hasError = false;
      })
      .addCase(fetchJson.fulfilled, (state, action) => {
        state.isLoading = false;
        state.memes = action.payload;
      })
      .addCase(fetchJson.rejected, (state, action) => {
        state.isLoading = false;
        state.hasError = true;
        state.memes = {};
      });
  }
});

export default loadJsonSlice.reducer;

export const selectAllJson = (state) => state.loadJsonReducer.memes;

export const isLoading = (state) => state.loadJsonReducer.isLoading;

display.js

import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { selectAllJson, isLoading, fetchJson } from "./jsonSlice";
const DisplayJson = () => {
  const allMemes = useSelector(selectAllJson);
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchJson());
    console.log(allMemes.data.memes[0].id); //Here is where the code gives error.
  }, [dispatch]);

  if (useSelector(isLoading)) {
    return <h1 style={{ fontSize: "48px" }}>WAIT PUST</h1>;
  }
  return <div>{allMemes.data.memes[0].id}</div>; //Here is where the code gives error.
};
export default DisplayJson;

store.js

import { configureStore } from "@reduxjs/toolkit";
import loadJsonSlice from "./jsonSlice";
const store = configureStore({
  reducer: {
    loadJsonReducer: loadJsonSlice
  }
});
export default store;

2 Answers2

1

I believe you have a small miss-understanding of how asynchronicity works in JavaScript.

Your code in the slide.js is correct and will work.

However, your display.js has to wait for the asynchronous action to complete before it can access the state.


useEffect(() => {
    // This dispatch will return a Promise, only after the promise resolves  you can access the data
    dispatch(fetchJson());
    console.log(allMemes.data.memes[0].id); //Here is where the code gives error.
  }, [dispatch]);

Make sure you check whether allMemes is already populated when you access it:

const allMemes = useSelector(selectAllJson);

console.log('memes: ', allMemes); // initially 'undefined' but eventually populated via your thunk

// When using memes, make sure it is populated
return allMemes ? allMemes.data.memes[0].id : 'Loading...';
MarcRo
  • 2,434
  • 1
  • 9
  • 24
  • Sir you are my hero! I have solved the issue with your help. I think it's my mistake to try learning difficult stuff when I am still freshman for the prerequisites. – Ahmet Ulutaş Dec 13 '21 at 12:50
0

I think this solution works, but the reason for the error is not the async type of your fetch request. The reason for this error is the current closure of your effect-function. Quoted by Eric Elliott:

"A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time."

See also this link: https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36

Depending on this, allMemes in the effect-function will be an empty object (like your initialization) also by dispatching an action-object and not a thunk.

Fabo95
  • 1
  • 1
  • 1