admin管理员组

文章数量:1310392

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 badges
Add a comment  | 

2 Answers 2

Reset to default 0

Issue

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"

本文标签: reactjsRedux Persisted Data Not Saving on ReloadStack Overflow