1

I am trying to move the asynchronous Axios POST request logic from my registration component into a thunk via the createAsyncThunk.

Here is my registration component

import React from 'react';
import axios from 'axios';
import { useDispatch, useSelector } from 'react-redux';
import { setUserProperty } from '../../features/user/registrationSlice';

const Registration = (props) => {
  const dispatch = useDispatch();

  const user = useSelector((state) => state);

  const { email, password, password_confirmation } = user;
  const handlChange = (event) => {
    dispatch(
      setUserProperty({
        name: event.target.name,
        value: event.target.value,
      }),
    );
  };

  const handleSubmit = (event) => {
    axios
      .post(
        'http://localhost:3001/registrations',
        {
          user: {
            email,
            password,
            password_confirmation,
          },
        },
        { withCredentials: true },
      )
      .then((response) => {
        if (response.data.status === 'created') {
          props.handleSuccessfulAuth(response.data);
        }
      })
      .catch((error) => {
        console.log('registration error', error);
      });
    event.preventDefault();
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="email"
          name="email"
          placeholder="Email"
          value={email}
          onChange={handlChange}
          required
        />

        <input
          type="password"
          name="password"
          placeholder="Password"
          value={password}
          onChange={handlChange}
          required
        />

        <input
          type="password"
          name="password_confirmation"
          placeholder="Confirm Password"
          value={password_confirmation}
          onChange={handlChange}
          required
        />

        <button tupe="submit">Register</button>
      </form>
    </div>
  );
};

export default Registration;

and here is what I was able to come up using documentation from the createAsyncThunk

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

export const getUsers = createAsyncThunk('registration/getUsers', async () => {
  return axios
    .post(
      'http://localhost:3001/registrations',
      {
        user: {
          email,
          password,
          password_confirmation,
        },
      },
      { withCredentials: true },
    )
    .then((response) => {
      if (response.data.status === 'created') {
        return response.data;
      }
    });
});

const initialState = {
  user: {
    email: '',
    password: '',
    password_confirmation: '',
  },
  loading: false,
  error: null,
};

const registrationSlice = createSlice({
  name: 'registration',
  initialState,
  reducers: {
    setUsers: (state, action) => {
      const { email, password, password_confirmation } = action.payload;
      state = {
        email,
        password,
        password_confirmation,
      };
    },
    setUserProperty: (state, action) => {
      const { name, value } = action.payload;
      state[name] = value;
    },
    extrareducers: {
      [getUsers.pending]: (state, action) => {
        state.loading = true;
      },
      [getUsers.fulfilled]: (state, action) => {
        state.user = action.payload;
        state.loading = false;
      },
      [getUsers.rejected]: (state, action) => {
        state.error = action.error.message;
        state.loading = false;
      },
    },
  },
});

export const { setUsers, setUserProperty, getUsers } =
  registrationSlice.actions;

export default registrationSlice.reducer;

but anytime I run it I keep on getting errors, for example, I get the error that the email, password, and password_confirmation is not defined when I make the call inside the getUsers function, I understand why and is because I am not pulling the information from the user like I have I available in my registration component, but I have no clue as to how to fix it or make it work. I want to understand how to fix the problem.

Cosmel
  • 45
  • 9
  • [Drew Reese](https://stackoverflow.com/users/8690857/drew-reese) Would you take a look at this please – Cosmel Jun 30 '21 at 23:09

1 Answers1

1

In the payload creator you should access the thunkAPI to the getState method to access the stored registration.user state.

const {
  registration: {
    user: {
      email,
      password,
      password_confirmation
    },
  },
} = getState();
export const getUsers = createAsyncThunk(
  'registration/getUsers',
  async (arg, { getState }) => {
    const {
      registration: {
        user: {
          email,
          password,
          password_confirmation
        },
      },
    } = getState();

    return axios
      .post(
        'http://localhost:3001/registrations',
        {
          user: {
            email,
            password,
            password_confirmation,
          },
        },
        { withCredentials: true },
      )
      .then((response) => {
        if (response.data.status === 'created') {
          return response.data;
        }
      });
});

The extraReducers should be at the same level as the reducers key.

const registrationSlice = createSlice({
  name: 'registration',
  initialState,
  reducers: {
    setUsers: (state, action) => {
      const { email, password, password_confirmation } = action.payload;
      state.user = {
        email,
        password,
        password_confirmation,
      };
    },
    setUserProperty: (state, action) => {
      const { name, value } = action.payload;
      state.user[name] = value;
    },
  },
  extraReducers: {
    [getUsers.pending]: (state, action) => {
      state.loading = true;
    },
    [getUsers.fulfilled]: (state, action) => {
      state.user = action.payload;
      state.loading = false;
    },
    [getUsers.rejected]: (state, action) => {
      state.error = action.error.message;
      state.loading = false;
    },
  },
});
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • ok , after implementing the solution, I imported getUser into my Registration component and inside the handleSumbit i dispatch getUsers, when I tried to register a new user I open the redux dev tools and get the message the following "error(pin):"Cannot destructure property 'email' of 'user' as it is undefined." , the email get populated and the password and password confirmation as well but I get the action of getusers/rejected, any idea how I can fix it please – Cosmel Jul 01 '21 at 01:23
  • @Cosmel Shoot, I just realized your `email`, `password`, and `password_confirmation` state is nested in an `user` object. I updated my answer. Sorry for any confusion. – Drew Reese Jul 01 '21 at 01:46
  • man sorry for my ignorance, I keep on getting the same [link to error](https://www.screenpresso.com/=CcCLd), as you can see on the picture the state changes with the values of the user but i don't know how to fix this part – Cosmel Jul 01 '21 at 02:01
  • @Cosmel Ah, and sorry again, totally forgot the reducer itself, it's `state.registration.user`. IDE usually fills this in for me so I don't generally need to think about it much. – Drew Reese Jul 01 '21 at 02:48
  • man i really have no clue where I have to make that change. When you said the reducer itself I made the change in here [first try](https://www.screenpresso.com/=dKKmg), when that didn't work, then I added in here [second try](https://www.screenpresso.com/=6xIub), so instead of guessing where to make the change I rather ask you where, can you please tell me where I have to make the change for this to work – Cosmel Jul 01 '21 at 03:59
  • @Cosmel Change is in the action where you are accessing state. I [*thought I*] had updated my answer earlier [*but I forgot to click save*]. Use `getState` method to return the entire `state` object from the store, and access `state.registration.user`. In my answer I destructured `registration` from the returned state object, then destructured `user` from `registration`, and then finally the other fields from `user`. – Drew Reese Jul 01 '21 at 04:32