Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React/Redux Toolkit TypeScript issue with useDispatch `Expected 0 arguments, but got 1`

I am putting together a web app using React/Redux/TypeScript and I don’t have a lot of experience with TypeScript. For the register user flow I having an issue in my code where I get the error: Expected 0 arguments, but got 1.ts(2554) when I try to pass the new user form data to the dispatch function to pass to authSlice createAsyncThunk register function.

Below is the code:

authService.ts

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import axios from "axios";

const API_URL = "/api/users/";

//Register user
const register = async (userData: {} | null | unknown) => {
  const response = await axios.post(API_URL, userData);

  if (response.data) {
    localStorage.setItem("user", JSON.stringify(response.data));
  }
  return response.data;
};

const authService = {
  register,
};

export default authService;

authSlice.ts

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

export interface InitialState {
  user: {} | null;
  isError: boolean;
  isSuccess: boolean;
  isLoading: boolean;
  message: string | null | unknown;
}

//Get user from localStorage
const user = JSON.parse(localStorage.getItem("user") ?? "{}");

const initialState: InitialState = {
  user: user ? user : null,
  isError: false,
  isSuccess: false,
  isLoading: false,
  message: "",
};

//Register user
export const register = createAsyncThunk(
  "auth/register",
  async (user, thunkAPI) => {
    try {
      return await authService.register(user);
    } catch (error: any) {
      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString();
      return thunkAPI.rejectWithValue(message);
    }
  }
);

export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    reset: (state) => {
      state.isLoading = false;
      state.isSuccess = false;
      state.isError = false;
      state.message = "";
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(register.pending, (state) => {
        state.isLoading = true;
      })
      .addCase(register.fulfilled, (state, action) => {
        state.isLoading = false;
        state.isSuccess = true;
        state.user = action.payload;
      })
      .addCase(register.rejected, (state, action) => {
        state.isLoading = false;
        state.isError = true;
        state.message = action.payload;
        state.user = null;
      });
  },
});

export const { reset } = authSlice.actions;
export default authSlice.reducer;

Register.tsx

import React from "react";
import { useState, useEffect } from "react";
import { FaUser } from "react-icons/fa";
import { useSelector, useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import { RootState } from "../app/store";
import { useAppSelector, useAppDispatch } from "../app/hooks";
import authService from "../features/auth/authService";
import { register, reset } from "../features/auth/authSlice";

export default function Register() {
  interface FormData {
    name: string;
    email: string;
    password: string;
    password2: string;
  }

  const [formData, setFormData] = useState<FormData>({
    name: "",
    email: "",
    password: "",
    password2: "",
  });

  const { name, email, password, password2 } = formData;

  const navigate = useNavigate();
  const dispatch = useAppDispatch();

  const { user, isLoading, isError, isSuccess, message } = useSelector(
    (state: RootState) => state.auth
  );

  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setFormData((prevState) => ({
      ...prevState,
      [e.target.name]: e.target.value,
    }));
  };

  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    console.log(formData);

    if (password !== password2) {
      toast.error("Passwords don't match");
    } else {
      const newUser = {
        name,
        email,
        password,
      };
      dispatch(register(newUser));
    }

    setFormData({
      name: "",
      email: "",
      password: "",
      password2: "",
    });
  };

  return (
    <div className="flex flex-col mt-20 mb-16 mx-auto items-center w-full max-w-2xl border p-6 rounded-md bg-[#f0eff4] shadow-md">
      <section className="flex flex-col items-center text-2xl font-medium mb-12 mt-12 p-4">
        <h1 className="flex items-center text-5xl mb-6 text-[#003049]">
          <FaUser className="flex items-center align-middle mr-4" /> Register
        </h1>
        <p className="text-5xl text-[#003049]">Please create an account</p>
      </section>
      <section className="w-full mb-16">
        <form onSubmit={onSubmit} className="w-7/10 mx-auto">
          <div>
            <input
              type="text"
              id="name"
              name="name"
              value={name}
              placeholder="Enter name"
              onChange={onChange}
              className="w-full p-2.5 border border-gray-300 rounded-md mb-4 font-inherit"
            />
          </div>
          <div>
            <input
              type="email"
              id="email"
              name="email"
              value={email}
              placeholder="Enter email"
              onChange={onChange}
              className="w-full p-2.5 border border-gray-300 rounded-md mb-4 font-inherit"
            />
          </div>
          <div>
            <input
              type="password"
              id="password"
              name="password"
              value={password}
              placeholder="Enter password"
              onChange={onChange}
              className="w-full p-2.5 border border-gray-300 rounded-md mb-4 font-inherit"
            />
          </div>
          <div>
            <input
              type="password"
              id="password2"
              name="password2"
              value={password2}
              placeholder="Re-enter password"
              onChange={onChange}
              className="w-full p-2.5 border border-gray-300 rounded-md mb-4 font-inherit"
            />
          </div>
          <div>
            <button
              type="submit"
              className="py-3 px-4 w-full rounded-md text-white text-center cursor-pointer flex items-center justify-center bg-[#003049] border-[#003049] hover:text-[#f77f00]"
            >
              Submit
            </button>
          </div>
        </form>
      </section>
    </div>
  );
}

The error is occurring in the dispatch(register(newUser)) line. Specifically newUser is showing the error Expected 0 arguments, but got 1.ts(2554)

I have read all of the Redux/Typescript docs and searched this site but could not find a solution that has worked so far.

>Solution :

The issue is most likely that your register thunk does not have a type declared for the user argument.

Currently, it’s:

export const register = createAsyncThunk(
  "auth/register",
  async (user, thunkAPI) => {
    // snip body
  }
)

Per our TS usage docs for createAsyncThunk, at a minimum you need to declare a type for the first argument of the payload function – in this case, user:

interface User {
  // fields
}

export const register = createAsyncThunk(
  "auth/register",
  async (user: User, thunkAPI) => {
    // snip body
  }
)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading