I'm trying to build my first react app, and I'm following some standart libraries and their quick start quides but for the react-redux
and @reduxjs/toolkit
, there's this error that I couldn't figure out why it shows in the first place:
Invalid hook call. Hooks can only be called inside of the body of a function component.
This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
Relevant files:
../../redux/stateSlices/user.slice
import { createSlice } from "@reduxjs/toolkit";
export const userSlice = createSlice({
name: "user",
initialState: {
loggedInUser: null
},
reducers: {
logToConsole: (state, action) => {
console.log("tryout", state, action.payload);
}
}
});
export const {
logToConsole
} = userSlice.actions;
export default userSlice.reducer;
../../redux/store
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './stateSlices/user.slice';
export const store = configureStore({
reducer: {
user: userReducer
}
});
./pages/register/register
import React, { useState } from 'react'
import {
signIn,
createUser,
deleteUser
} from '../../services/user.service';
import { useDispatch, useSelector } from 'react-redux';
import { Navigate, Link } from 'react-router-dom';
import {
logToConsole
} from '../../redux/stateSlices/user.slice';
export function Register() {
const [errorMessage, setErrorMessage] = useState('');
const [Username, setUsername] = useState('');
const [MailAddress, setMailAddress] = useState('');
const [Password, setPassword] = useState('');
const [Name, setName] = useState('');
const [Surname, setSurname] = useState('');
const dispatch = useDispatch();
const user = useSelector((state) => state.loggedInUser);
const RegisterUser = (e) =>
{
e.preventDefault();
try
{
console.log("user", user);
if(/^\w ([\.-]?\w )*@\w ([\.-]?\w )*(\.\w{2,3}) $/.test(MailAddress))
{
var createUserResponse = createUser(
Username,
MailAddress,
Name,
Surname,
Password,
Username === 'admin' ? 999999999 : 0
);
if(createUserResponse.Status)
{
dispatch(logToConsole(1));
Navigate({ to: "/" });
}
else
{
if(createUserResponse.ErrorList)
{
setErrorMessage(createUserResponse.ErrorList.join(','));
}
else
{
setErrorMessage("Kayıt işlemi sırasında beklenmedik bir hata yaşandı, daha sonra tekrar deneyiniz.");
}
}
}
else
{
setErrorMessage("Geçersiz mail adresi.");
}
}
catch(err)
{
if(err.code === 'duplicateValue')
{
setErrorMessage(err.ErrorList.join(','));
}
else
{
deleteUser(MailAddress);
setErrorMessage(err.message);
}
}
}
return (
<div className="login-page">
<div className='container d-flex align-items-center'>
<div className='form-holder has-shadow'>
<div className="row">
<div >
<div >
<div >
<div >
<h1>appName</h1>
</div>
</div>
</div>
</div>
<div >
<div >
<div >
<div className="col-12 text-white ff-arial text-center"><h3>Kaydol</h3></div>
{
errorMessage &&
<span className='col-12 text-white pl-0 pb-3 m-0'> { errorMessage } </span>
}
<div >
<input
id="login-name"
type="text"
name="loginName"
required
data-msg="Lütfen adınızı adresinizi eksiksiz bir şekilde giriniz."
value={Name}
onChange={(e) => setName(e.target.value)}/>
<label for="login-name" >Ad</label>
</div>
<div >
<input
id="login-surname"
type="text"
name="loginSurname"
required
data-msg="Lütfen soyadınızı adresinizi eksiksiz bir şekilde giriniz."
value={Surname}
onChange={(e) => setSurname(e.target.value)}/>
<label for="login-surname" >Soyad</label>
</div>
<div >
<input
id="login-userName"
type="text"
name="loginUsername"
required
data-msg="Lütfen kullanıcı adınızı adresinizi eksiksiz bir şekilde giriniz."
value={Username}
onChange={(e) => setUsername(e.target.value)}/>
<label for="login-userName" >Kullanıcı adı</label>
</div>
<div >
<input
id="login-mail"
type="text"
name="loginMailAddress"
required
data-msg="Lütfen e-mail adresinizi eksiksiz bir şekilde giriniz."
value={MailAddress}
onChange={(e) => setMailAddress(e.target.value)}/>
<label for="login-mail" >Mail Adresi</label>
</div>
<div >
<input
id="login-password"
type="password"
name="loginPassword"
required
data-msg="Şifrenizi eksiksiz olarak giriniz."
value={Password}
onChange={(e) => setPassword(e.target.value)}/>
<label for="login-password" >Şifre</label>
</div>
<button className='btn btn-block btn-primary' onClick={(e) => RegisterUser(e)}>Kaydol</button>
<div className="col-12 mt-3 text-center text-white">
<span>veya <Link to="/login" className='ml-1'>Giriş Yap</Link></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {
BrowserRouter,
Routes,
Route
} from 'react-router-dom';
import { store } from './redux/store';
import { Provider } from 'react-redux';
import { Register } from './pages/register/register';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<BrowserRouter>
<Routes>
<Route path='/' element={<App/>}>
<Route path='/' element={<Index/>}></Route>
</Route>
<Route path='register' element={<Register/>} ></Route>
</Routes>
</BrowserRouter>
</Provider>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint.
package.json
{
"name": "appName",
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.8.2",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
"i": "^0.3.7",
"react-redux": "^8.0.2",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"web-vitals": "^2.1.4"
},
"peerDependencies": {
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint-plugin-react-hooks": "^4.5.0"
}
}
For the register.js
file, when I add the dispatch()
method on button.onClick
directly like this, it doesn't give the error:
<button className='btn btn-block btn-primary' onClick={(e) => dispatch(logToConsole(1))}>Kaydol</button>
But I need to use the dispatch
method inside my custom function, as can be seen on their quick start guide.
I tried this but it didn't work. Also, as far as I know so far, I am using it inside a functional component.
What am I doing wrong here?
CodePudding user response:
Your error is caused by this
Navigate({ to: "/" });
This is the incorrect way to use Navigate
. I think based on your code you want to use the hook useNavigate()
instead
Also your redux is incorrect (not causing your error but...)
const user = useSelector((state) => state.loggedInUser);
user would always be undefined because in your reducer you don't have a state called loggedInUser
you only have user
that points to your userReducer.
This should give you what you want:
const user = useSelector((state) => state.user.loggedInUser);