Reputation: 1309
I'm trying to learn redux toolkit
What I want to achieve: When the app is started run the check() function, retireve saved credentials via getCredentials, if they exist (!=null) log in with those credentials, if not show the login screen (the login screen in visible when isAuthenticated === false)
I get the following error:
Require cycle: state\reducers\authSlice.ts -> state\store.ts -> state\reducers\authSlice.ts
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle.
ERROR TypeError: undefined is not an object (evaluating '_authSlice.default.reducer')
If I comment out store.dispatch then the code runs without errors.
Here is the code:
store.tsx
import { configureStore } from "@reduxjs/toolkit";
import authSlice from "./reducers/authSlice";
export const store = configureStore({
reducer: {
auth: authSlice.reducer
}
});
export async function getStore(){
return store;
}
setImmediate(()=>{
store.dispatch(authSlice.actions.check());
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
authSlice.tsx
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit'
import { store } from '../store';
import { isAuthenticated, login } from '../../api/auth';
import { getCredentials, saveCredentials } from '../../storage/auth';
import { Credentials } from '../../interfaces/auth';
interface AuthState {
isAuthenticated?: boolean
username?: string
}
const initialState: AuthState = {
isAuthenticated: undefined,
username: undefined
}
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
check(state){
if (state.isAuthenticated == undefined){
getCredentials().then(auth=>{
if (auth){
login(auth).then(()=>{
store.dispatch(authSlice.actions.loginSuccess(auth))
})
} else {
store.dispatch(authSlice.actions.unauthenticated())
}
})
}
},
loginSuccess(state,action: PayloadAction<Credentials>){
state.username = action.payload.username;
state.isAuthenticated = true;
},
unauthenticated(state){
state.isAuthenticated = false;
},
},
});
export default authSlice;
Some people say calling store.dispatch from a reducer is an antipattern, but how else an I supposed to achieve the same logic?
Upvotes: 1
Views: 1195
Reputation: 44086
A reducer has to be pure. That means (among others) two things:
getCredentials
or login
in there and generally no async logic at all).You are missing quite a few basics here, so I would suggest that maybe you follow the official Redux Essentials Tutorial and read up how you should do things like side effects. That kind of logic has no place in a reducer.
Upvotes: 1