Search code examples
javascriptreactjsreduxredux-thunk

How to reload data from api in Redux


when I lose in a hangman I want to reload my data in the API so that a new password appears. Unfortunately I have no idea how to reload it without reloading the whole page, is it even possible to run the api again on a button click for example?

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

const url = 'https://random-word-api.herokuapp.com/word?number=1';

const initialState = {
    password: '1',
    misstake: 0,
    usedChart: [],
};

export const getPassword = createAsyncThunk(
    'hangman/getPassword',
    async (thunkAPI) => {
        console.log(1)
        try {
            const resp = await axios(url)
            return resp.data
        } catch(error){
            return thunkAPI.rejectWithValue('api not working');
        }
    }
);

const HangManSlice = createSlice({
    name: 'hangman',
    initialState,
    reducers: {
        increaseError: (state) => {
            state.misstake += 1
        },
        usedCharts: (state, action) => {
            state.usedChart.push(action.payload)
        },
        restart: (state) => {
            state.misstake = 0
            state.usedChart = []
            getPassword()
        }
    },
    extraReducers: (builder) => {
        builder
            .addCase(getPassword.fulfilled, (state, action) => {
                state.password = action.payload;
            })
    }
})

export const { increaseError, usedCharts, restart } = HangManSlice.actions

export default HangManSlice.reducer

Solution

  • You should dispatch the getPassword() from the "restart" button handler instead of calling it your reducer.

    const RestartButton = () => {
      const dispatch = useDispatch();
    
      const restartHandler = () => {
        dispatch(getPassword());
        dispatch(restart())
      };
     
      return (
        <button onClick={restartHandler}>Restart</button>
      );
    }
    

    Another option is to use the getPassword thunk to initialize a new game like so:

    import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
    import axios from 'axios';
    
    const url = 'https://random-word-api.herokuapp.com/word?number=1';
    
    const initialState = {
        loading: false,
        password: '1',
        misstake: 0,
        usedChart: [],
    };
    
    export const startGame = createAsyncThunk(
        'hangman/getPassword',
        async (thunkAPI) => {
            console.log(1)
            try {
                const resp = await axios(url)
                return resp.data
            } catch(error){
                return thunkAPI.rejectWithValue('api not working');
            }
        }
    );
    
    const HangManSlice = createSlice({
        name: 'hangman',
        initialState,
        reducers: {
            increaseError: (state) => {
                state.misstake += 1
            },
            usedCharts: (state, action) => {
                state.usedChart.push(action.payload)
            },
        },
        extraReducers: (builder) => {
            builder
                .addCase(startGame.pending, (state, action) => {
                    state.loading = true;
                })
                .addCase(startGame.rejected, (state, action) => {
                    state.loading = false;
                })
                .addCase(startGame.fulfilled, (state, action) => {
                    state.loading = false;
    
                    // store new password
                    state.password = action.payload;
    
                    // reset state
                    state.misstake = 0
                    state.usedChart = []
                })
        }
    })
    
    export const { increaseError, usedCharts, restart } = HangManSlice.actions
    
    export default HangManSlice.reducer
    

    Now you can dispatch startGame(), and the state will be reset with a new password.