javascriptreact-reduxredux-thunkredux-toolkit

Problems with createAsyncThunk


I have just completed Learn Redux on Codecademy and want to that knowledge in practice. But I have an error. When I create extraReducers for updating the state to actual promise status it does not add information.

getUserSlice.js

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { fetchUserInfo } from '../../api';

export const loadUser = createAsyncThunk("getUser/loadUser",
    async (arg, thunkAPI) => {
        return await fetchUserInfo();
        
    }
});
const sliceOptions = {
  name: 'getUser',
  initialState: {
    info: [],
    isLoading: false,
    hasError: false,
  },
  reducers: {},
   extraReducers: (builder) => {
        builder
            .addCase(loadUser.pending, (state) => {
            state.isLoading = true;
            state.hasError = false;
            })
            .addCase(loadUser.fulfilled, (state, action) => {
            state.info.push(action.payload)
            
            state.isLoading = false;
            state.hasError = false;
            })
            .addCase(loadUser.rejected, (state, action) => {
            state.isLoading = false;
            state.hasError = true;
            })
    },
};

export const getUserSlice = createSlice(sliceOptions);
console.log(getUserSlice);

export const selectUserInfo = (state) => {
  console.log(state);
  return state;
};

export default getUserSlice.reducer;

api.js

export const fetchUserInfo = async () => {
   const user = await fetch('http://localhost:5000/api/user');
   const json = user.json();

   return json;
}

App.js

import React from 'react';
import './App.css';

import {Container} from 'react-bootstrap';
import Achievement from './components/Achievement/Achievement';
import { useSelector } from 'react-redux';
import { selectUserInfo } from './features/getUser/getUserSlice';



const colors = ['#010626','#4d6396', '#5d1a87', '#5d1a87', '#5d1a87'];

function App() {
 
   
  let color= colors[0];
  const user = useSelector(selectUserInfo)
  function changeColor() {
    const newColor = `rgb(${Math.round(Math.random() *256)}, ${Math.round(Math.random() *256)}, ${Math.round(Math.random() *256)})`;
    
    color = newColor;
  }
  
    return (
      <div className="App" style={{ background: color }}>
          <Container>
            <h1 id="whoAmI">
              Witaj na moim portfolio
              {user}
            </h1>
            <button onClick={changeColor}>
              Zmień kolor tła
            </button>
            <div className="col-lg-4 col-md-6 col-sm-12">
              <Achievement title="Ukończenie The Web Developer Bootcamp" picture="https://res.cloudinary.com/syberiancats/image/upload/v1630317595/k9g0nox2fyexxawg8whu.jpg" />
            </div>
          </Container>
         
         
      </div>
    );
  

  
  
}

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import reportWebVitals from './reportWebVitals';
import { store } from './store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);


reportWebVitals();

store.js

import { configureStore } from "@reduxjs/toolkit";
import getUserReducer from "./features/getUser/getUserSlice";

export const store = configureStore({
    reducer: {
        getUser: getUserReducer
    }
})

Console.log of getUserSlice and state in the selector

console log (getUserSlice and second state)


Solution

  • Maybe you can use (builder) => {} function in extraReducer and you edit your loadUser because your Api.js already return json like code below:

    import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
    import { fetchUserInfo } from '../../api';
    
    export const loadUser = createAsyncThunk('getUser/loadUser', async (arg, thunkAPI) => {
      return await fetchUserInfo();
    });
    const sliceOptions = {
      name: 'getUser',
      initialState: {
        info: [],
        isLoading: false,
        hasError: false,
      },
      reducers: {},
      extraReducers: (builder) => {
      builder
        .addCase(loadUser.pending, (state) => {
         state.isLoading = true;
         state.hasError = false;
        })
        .addCase(loadUser.fulfilled, (state, action) => {
         state.info.push(action.payload)
         
         state.isLoading = false;
         state.hasError = false;
        })
        .addCase(loadUser.rejected, (state, action) => {
         state.isLoading = false;
         state.hasError = true;
        })
      },
    };
    
    export const getUserSlice = createSlice(sliceOptions);
    console.log(getUserSlice);
    
    export const selectUserInfo = (state) => {
      console.log(state);
      return state;
    };
    
    export default getUserSlice.reducer;
    

    and you maybe forgot to add await before fetch, you should edit your fetching data in api.js into this below:

    export const fetchUserInfo = async () => {
       const user = await fetch('http://localhost:5000/api/user');
       const json = user.json();
    
       return json;
    }