I've looked at a number of forum posts prior to posting and still have not found a solution. I am storing data using Redux which is working as intended. I store it in SignIn.js and after navigating to another page it is saved, but upon refreshing the page the data does not persist. I've tried with and without the whitelisting parameter. Below is my code:
persistStorage.js
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistCombineReducers } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import authReducer from './authStorage'
const persistConfig = {
key: 'root',
storage,
serializableCheck: {
ignoredActions: ['SOME_ACTION'],
warnOnly: true,
}
};
const persistedReducer = persistCombineReducers(persistConfig, authReducer);
const store = configureStore({
reducer: persistedReducer
});
export const persistor = persistStore(store);
authStorage.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
token: "",
id: ""
};
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setToken(state, action) {
state.token = action.payload;
},
setID(state, action) {
state.id = action.payload;
},
clear(state) {
state.token = null;
state.id = null;
},
},
});
SignIn.js
export const { setToken, setID, clear } = authSlice.actions;
export default authSlice.reducer;
import { useState, useRef } from "react";
import { useMutation } from "@apollo/client";
import { useNavigate } from "react-router-dom";
import { useCookies } from "react-cookie";
import Header from '../components/Header';
import InputField from "../components/InputField";
import { useDispatch, useSelector } from 'react-redux';
import { auth } from "../../index";
import { setToken, setID } from '../../authStorage';
import { SIGN_IN } from "../../queries/accountQueries.js";
import "../../style/signIn.css";
function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [ signIn, { data, loading, error }] = useMutation(SIGN_IN);
const [ cookies, setCookie ] = useCookies(['session'])
const navigate = useNavigate();
const dispatch = useDispatch();
let signedIn = useRef(false);
const setValue = (newValue, valueType) => {
if (valueType === "Email") setEmail(newValue);
else setPassword(newValue);
}
if (loading) return <p>Loading...</p>;
else if (error) {
alert("error");
return <p>Error :({JSON.stringify(error, null, 2)}</p>;
}
else if (data != undefined && !signedIn.current) {
signedIn.current = true
dispatch(setToken(data.employeeSignIn.auth)); // stores data with Redux
dispatch(setID(data.employeeSignIn.id));
auth.signInKey = null;
setCookie("session", data.employeeSignIn.session, {
options: {
maxAge: 7200
}
})
navigate('/two-factor-auth');
}
return(
<>
<Header view={false} />
<div className="content centered flex col">
<form className="centered" onSubmit={(e) => {
e.preventDefault();
auth.signInKey = process.env.REACT_APP_SIGN_IN_KEY;
signIn({
variables: {
email: email,
password: password
}
})
}}>
<h2>Sign in</h2>
<InputField label="Email" value={email} onChangeState={setValue} />
<InputField type="password" label="Password" value={password} onChangeState={setValue} />
<input type="submit" className="button centered"/>
</form>
</div>
</>
)
}
export default SignIn;
index.js
root.render(
<ApolloProvider client={client}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RouterProvider router={router} />
</PersistGate>
</Provider>
</ApolloProvider>
);
Some of the posts I've looked at already:
Persist Store with Redux in React Native
Passing reducer name to Redux-persist whitelist is not working
redux-persist is not saving my redux state when I refresh or close my react-native app
I've looked at a number of forum posts prior to posting and still have not found a solution. I am storing data using Redux which is working as intended. I store it in SignIn.js and after navigating to another page it is saved, but upon refreshing the page the data does not persist. I've tried with and without the whitelisting parameter. Below is my code:
persistStorage.js
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistCombineReducers } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import authReducer from './authStorage'
const persistConfig = {
key: 'root',
storage,
serializableCheck: {
ignoredActions: ['SOME_ACTION'],
warnOnly: true,
}
};
const persistedReducer = persistCombineReducers(persistConfig, authReducer);
const store = configureStore({
reducer: persistedReducer
});
export const persistor = persistStore(store);
authStorage.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
token: "",
id: ""
};
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setToken(state, action) {
state.token = action.payload;
},
setID(state, action) {
state.id = action.payload;
},
clear(state) {
state.token = null;
state.id = null;
},
},
});
SignIn.js
export const { setToken, setID, clear } = authSlice.actions;
export default authSlice.reducer;
import { useState, useRef } from "react";
import { useMutation } from "@apollo/client";
import { useNavigate } from "react-router-dom";
import { useCookies } from "react-cookie";
import Header from '../components/Header';
import InputField from "../components/InputField";
import { useDispatch, useSelector } from 'react-redux';
import { auth } from "../../index";
import { setToken, setID } from '../../authStorage';
import { SIGN_IN } from "../../queries/accountQueries.js";
import "../../style/signIn.css";
function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [ signIn, { data, loading, error }] = useMutation(SIGN_IN);
const [ cookies, setCookie ] = useCookies(['session'])
const navigate = useNavigate();
const dispatch = useDispatch();
let signedIn = useRef(false);
const setValue = (newValue, valueType) => {
if (valueType === "Email") setEmail(newValue);
else setPassword(newValue);
}
if (loading) return <p>Loading...</p>;
else if (error) {
alert("error");
return <p>Error :({JSON.stringify(error, null, 2)}</p>;
}
else if (data != undefined && !signedIn.current) {
signedIn.current = true
dispatch(setToken(data.employeeSignIn.auth)); // stores data with Redux
dispatch(setID(data.employeeSignIn.id));
auth.signInKey = null;
setCookie("session", data.employeeSignIn.session, {
options: {
maxAge: 7200
}
})
navigate('/two-factor-auth');
}
return(
<>
<Header view={false} />
<div className="content centered flex col">
<form className="centered" onSubmit={(e) => {
e.preventDefault();
auth.signInKey = process.env.REACT_APP_SIGN_IN_KEY;
signIn({
variables: {
email: email,
password: password
}
})
}}>
<h2>Sign in</h2>
<InputField label="Email" value={email} onChangeState={setValue} />
<InputField type="password" label="Password" value={password} onChangeState={setValue} />
<input type="submit" className="button centered"/>
</form>
</div>
</>
)
}
export default SignIn;
index.js
root.render(
<ApolloProvider client={client}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RouterProvider router={router} />
</PersistGate>
</Provider>
</ApolloProvider>
);
Some of the posts I've looked at already:
Persist Store with Redux in React Native
Passing reducer name to Redux-persist whitelist is not working
redux-persist is not saving my redux state when I refresh or close my react-native app
Share Improve this question asked Feb 3 at 19:32 mfuscomfusco 572 silver badges11 bronze badges2 Answers
Reset to default 0Issue
The issue is that you are using persistCombineReducers
which expects to consume an object of ReducersMapObject
, specifically
ReducersMapObject<CombinedState<S>, Action<any>>
https://github/rt2zz/redux-persist/blob/d8b01a085e3679db43503a3858e8d4759d6f22fa/src/persistCombineReducers.ts#L10-L21
// combineReducers + persistReducer with stateReconciler defaulted to autoMergeLevel2 // eslint-disable-next-line @typescript-eslint/no-unused-vars export default function persistCombineReducers<S, A extends Action>( config: PersistConfig<any>, reducers: ReducersMapObject<CombinedState<S>, Action<any>> ): Reducer<any, AnyAction> { config.stateReconciler = config.stateReconciler === undefined ? autoMergeLevel2 : config.stateReconciler return persistReducer(config, combineReducers(reducers)) }
but you are passing it a reducer function, e.g.
Reducer<
{ token: string; id: string; },
UnknownAction,
{ token: string; id: string; }
>
The result is that your store is malformed and none of your state is persisted to storage:
Store | |
Storage |
Solution Suggestion
Either pass an object of reducers to persistCombineReducers
:
const persistedReducer = persistCombineReducers(persistConfig, {
auth: authReducer,
});
Store | |
Storage |
or use persistReducers
to handle the single auth reducer function:
import { persistStore, persistReducer } from "redux-persist";
...
const persistedReducer = persistReducer(persistConfig, authReducer);
Store | |
Storage |
The issue was that I imported store
from a separate file than from persistStorage
in index.js
.
I had this:
import store from './store'
import { persistor } from "./persistStorage"
I should have had this:
import { persistor, store } from "./persistStorage"