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
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.
CodePudding user response:
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
}
)