Redux-persist not persisting with expo on reload - react-native

I am using following tech stack
react-native
expo
redux
redux-persist.
I have tried articles, docs as well as questions here also but not help. Its simply not persisting. I am using emulator and running through expo only. As soon i close the app and reload expo client it simply doesn't persist and ask me to login again.
I also tried using AsyncStorage but still not working.
Hers's my code:
index.js
import thunk from "redux-thunk";
import AsyncStorage from "#react-native-community/async-storage";
import ExpoFileSystemStorage from "redux-persist-expo-filesystem"
// import storage from 'redux-persist/lib/storage';
import { createStore, applyMiddleware, compose } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import rootReducer from "./reducers/rootReducer";
import logger from "redux-logger";
const persistConfig = {
key: "root",
storage: ExpoFileSystemStorage,
whitelist: ["authReducer"],
};
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(
persistedReducer,
composeEnhancers(applyMiddleware(thunk, logger))
);
let persistor = persistStore(store);
export { store, persistor };
app.js
import React from "react";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { AppLoading } from "expo";
import { useFonts } from "#use-expo/font";
import { NavigationContainer } from "#react-navigation/native";
import { ThemeProvider } from "react-native-elements";
import { theme } from "./constants/ThemeConfiguration";
import { store, persistor } from "./store";
import RootNavigator from "./navigators/RootNavigator";
export default (App) => {
let [fontsLoaded] = useFonts({
"Lato-Regular": require("./assets/fonts/Lato-Regular.ttf"),
});
if (!fontsLoaded) {
return <AppLoading />;
} else {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ThemeProvider theme={theme}>
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</ThemeProvider>
</PersistGate>
</Provider>
);
}
};
rootReducer.js
import thunk from "redux-thunk";
import AsyncStorage from "#react-native-community/async-storage";
import { createStore, applyMiddleware, compose } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import rootReducer from "./reducers/rootReducer";
import logger from "redux-logger";
const persistConfig = {
key: "auth",
storage: AsyncStorage,
};
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(
persistedReducer,
composeEnhancers(applyMiddleware(thunk, logger))
);
let persistor = persistStore(store);
export { store, persistor };

I got it fixed. Its not there in any documentation or article. The problem is with the persistConfig. Key which is root here. It should be the name of the reducer which we want to persist. In my case it was auth.
Updated persistConfig will be as follows:
const persistConfig = {
key: "auth",
storage: AsyncStorage,
};

Related

Trying to navigate from a component that doesn't have the navigation props

I was working on my Authentication and when I was trying to work on the Auto Logout I had some Problems , I coded the functions needed to logout after the expiry time but when I wanted to Navigate back to the login screen after the logout i couldn't because of the Component i was working on ( doesn't have the navigation prop) , I used the docs but still didn't work !
this is my code
import { useSelector } from "react-redux";
import RootNavigation from "./ShopNavigation";
import { NavigationActions } from "#react-navigation/native";
import { createNavigationContainerRef } from "#react-navigation/native";
export const navigationRef = createNavigationContainerRef();
const NavigationContainer = (props) => {
const isAuth = useSelector((state) => !!state.auth.token);
function navigate(name) {
if (navigationRef.isReady()) {
navigationRef.navigate(name);
}
}
useEffect(() => {
if (!isAuth) {
navigate("Login");
}
}, [isAuth]);
return <RootNavigation />;
};
export default NavigationContainer;
And this is the App.js
import { StatusBar } from "expo-status-bar";
import { StyleSheet } from "react-native";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import AppLoading from "expo-app-loading";
import * as Font from "expo-font";
import productsReducer from "./store/reducers/products";
import { composeWithDevTools } from "redux-devtools-extension";
import RootNavigation from "./navigation/ShopNavigation";
import cartReducer from "./store/reducers/cart";
import { useState } from "react";
import ordersReducer from "./store/reducers/orders";
import AuthReducer from "./store/reducers/Auth";
import ReduxThunk from "redux-thunk";
import NavigationContainer from "./navigation/NavigationContainer";
const rootReducer = combineReducers({
products: productsReducer,
cart: cartReducer,
orders: ordersReducer,
auth: AuthReducer,
});
const store = createStore(
rootReducer,
applyMiddleware(ReduxThunk),
composeWithDevTools()
);
const fetchFonts = () => {
return Font.loadAsync({
"open-sans": require("./assets/fonts/OpenSans-Regular.ttf"),
"open-sans-bold": require("./assets/fonts/OpenSans-Bold.ttf"),
});
};
export default function App() {
const [fontLoaded, setfontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => setfontLoaded(true)}
onError={console.warn}
/>
);
}
return (
<Provider store={store}>
<NavigationContainer />
</Provider>
);
}
You can use the useNavigation hook for this purpose.
import { useNavigation } from '#react-navigation/native';
function View() {
const navigation = useNavigation();
return (
...
);
}
We can use it as usual, e.g.
navigation.navigate("...")

How to persist redux data in react native

I’ve been struggling on this problem for while n now it’s a pretty simple issue I need a way to persist my data from redux into react native’s local storage I have tried using multiple approaches like the redux-persist library but I still have not been able to crack it… has anyone found a solution to this issue, I’m open to all approaches.
Here is the code I used for the redux-persist library
store.ts
import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {persistStore} from 'redux-persist';
import authReducer from './reducers/authReducer';
import toastReducer from './reducers/toastReducer';
const rootReducer = combineReducers({
toast: toastReducer,
auth: authReducer,
});
export const Store = createStore(rootReducer, applyMiddleware(thunk));
export const PersistedStore = persistStore(Store);
export type RootState = ReturnType<typeof Store.getState>;
export type AppDispatch = typeof Store.dispatch;
authReducer.ts
import AsyncStorage from '#react-native-async-storage/async-storage';
import {persistReducer} from 'redux-persist';
import {AuthResponse} from '../../types/AuthResponse';
import {AuthReduxAction} from '../../types/ReduxActions';
import {SET_USER_DETAILS} from '../constants';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
};
interface State {
userDetails: AuthResponse;
}
const initialState: State = {
userDetails: {},
};
const authReducer: (
state: State,
action: AuthReduxAction,
) => State | Promise<State> = async (state = initialState, action) => {
switch (action.type) {
case SET_USER_DETAILS:
// Saving user details to local storage
return {...state, userDetails: action.payload};
default:
return state;
}
};
export default persistReducer(persistConfig, authReducer);
App.tsx
import React from 'react';
import Routes from './Routes';
import {Provider} from 'react-redux';
import {PersistGate} from 'redux-persist/integration/react';
import {LogBox} from 'react-native';
import {PersistedStore, Store} from './redux/store';
LogBox.ignoreLogs(['new NativeEventEmitter']);
const App = () => {
return (
<Provider store={Store}>
<PersistGate loading={null} persistor={PersistedStore}>
<Routes />
</PersistGate>
</Provider>
);
};
export default App;
Here is the response I get when I print out the data (auth data in this case) from the redux store:
{"_U": 0, "_V": 0, "_W": null, "_X": null, "_persist": {"rehydrated": true, "version": -1}}
Any help would be appreciated
Thanks
I would like to do redux-persist this way and it works for several projects. Check it out if it works for you.
store.js
import { applyMiddleware, createStore, compose } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import AsyncStorage from "#react-native-async-storage/async-storage";
import thunkMiddleware from "redux-thunk";
import { createLogger } from "redux-logger";
import reducer from "./reducers/";
const enhancers = [
applyMiddleware(
thunkMiddleware,
createLogger({
collapsed: true,
// eslint-disable-next-line no-undef
predicate: () => __DEV__,
})
),
];
/* eslint-disable no-undef */
const composeEnhancers =
(__DEV__ &&
typeof window !== "undefined" &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
/* eslint-enable no-undef */
const enhancer = composeEnhancers(...enhancers);
const persistConfig = {
key: "root",
storage: AsyncStorage,
blacklist: [],
};
const persistedReducer = persistReducer(persistConfig, reducer);
export const store = createStore(persistedReducer, {}, enhancer);
export const persistor = persistStore(store);
authReducer.js
import {AuthResponse} from '../../types/AuthResponse';
import {AuthReduxAction} from '../../types/ReduxActions';
import {SET_USER_DETAILS} from '../constants';
interface State {
userDetails: AuthResponse;
}
const initialState: State = {
userDetails: {},
};
const authReducer: (
state: State,
action: AuthReduxAction,
) => State | Promise<State> = async (state = initialState, action) => {
switch (action.type) {
case SET_USER_DETAILS:
// Saving user details to local storage
return {...state, userDetails: action.payload};
default:
return state;
}
};
export default authReducer;
index.js (same location as authReducer.js)
import { combineReducers } from 'redux';
import authReducer from './authReducer';
import toastReducer from './toastReducer';
export default combineReducers({
authReducer ,
toastReducer
});

store.dispatch is not a function - react native redux-persist with redux-thunk middlware

I am new to redux-persist and i am trying persist my states to local storage. Getting the above error.
I looked up in Stack Overflow for a solution but couldn't find a similar issue with a solution here. any help would be highly appreciated.
here is my store code:
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { createLogger } from "redux-logger";
import { createReactNavigationReduxMiddleware } from "react-navigation-redux-helpers";
import appReducer from "../reducers";
const persistConfig = {
key: 'tcroot',
storage: LocalStorage,
}
const persistedReducer = persistReducer(persistConfig, appReducer)
// instantiate logger middleware
const logger = createLogger();
const middleware = createReactNavigationReduxMiddleware(state => state.nav);
const composeEnhancers =
(typeof window !== "undefined" &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
const configureStore = () =>
createStore(
persistedReducer,
composeEnhancers(applyMiddleware(thunk, logger, middleware))
);
export default configureStore;
and my app.js code :
import React, { Component } from "react";
import { Provider } from "react-redux";
import { PersistGate } from 'redux-persist/integration/react'
import configureStore from "./redux/store";
// import store from "./redux/store/dev";
import persistor from './redux/store/persistedStore';
import AppContainer from "./screens/AppContainer";
// const { store, persistor } = configureStore();
const store = configureStore();
export default class App extends Component {
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<AppContainer />
</PersistGate>
</Provider>
);
}
}
The issue is your configureStore doesn't return persistor
Need like this
import { persistStore, persistReducer } from 'redux-persist'
//....
const configureStore = () => {
let store = createStore(
persistedReducer,
composeEnhancers(applyMiddleware(thunk, logger, middleware))
);
let persistor = persistStore(store)
return { store, persistor }
}

White flashes and white screen of death after the app opening after adding redux-persist

I'm getting white flashes and white screen of death after the app is opened second time after adding redux-persist.
Version of "redux-persist" is "^5.10.0".
Here is my App.js file:
import { PersistGate } from 'redux-persist/integration/react'
import {store, persistor } from './redux/store'
export default class App extends React.Component {
renderLoading = ()=> {
<View>
<ActivityIndicator size="large"/>
</View>
}
render() {
return(
<Provider store={store}>
<PersistGate loading={this.renderLoading()} persistor={persistor}>
<AppContainer/>
</PersistGate>
</Provider>
)
}
}
Here is my ./redux/store file:
import { createStore, applyMiddleware } from 'redux'
import { AsyncStorage } from 'react-native'
import thunkMiddleware from 'redux-thunk'
import { persistStore, persistReducer } from "redux-persist"
import reducers from './index';
import bindAuthEvents from '../auth/redux/bindEvents';
import bindTrackingEvents from '../tracking/redux/bindEvents';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
}
const persistedReducer = persistReducer(persistConfig, reducers)
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
export const store = createStoreWithMiddleware(persistedReducer);
const dispatch = event => store.dispatch(event)
const getState = () => store.getState()
bindAuthEvents(dispatch, getState);
bindTrackingEvents(dispatch, getState);
export const persistor = persistStore(store);
What can be the problem? and how is possible to fix it?
I had that issue but I solved using a loading component.
In the emulator it happens eventually but in physical devices not.

redux-persist: undefined is not an object (evaluating store.getState)

It's my first time using Redux and Redux Persist.
I got this error when I tried to run my application (in index.js line 20):
TypeError: undefined is not an object (evaluating 'store.getState')
index.js:
import React from 'react';
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import { Provider } from 'react-redux';
import {persistor, store}from './store/configureStore';
import { PersistGate } from 'redux-persist/integration/react';
const RNRedux = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App/>
</PersistGate>
</Provider>
)
AppRegistry.registerComponent(appName, () => RNRedux);
App.js:
import {createStackNavigator, createAppContainer} from 'react-navigation';
import Register from './components/Register';
import Home from './components/Home';
import Login from './components/Login';
const AppNavigator = createStackNavigator({
HomeScreen: {
screen: Home,
navigationOptions: {
title: 'Home',
header: null
}
},
LoginScreen: {screen: Login},
RegisterScreen: {
screen: Register,
navigationOptions: {
title: 'Register'
}
}
});
const App = createAppContainer(AppNavigator);
export default App;
configureStore.js:
import { createStore, combineReducers } from 'redux';
import userReducer from './reducers/user';
import { persistStore, persistCombineReducers, persistReducer } from 'redux-persist';
import storage from 'redux-persist/es/storage' // default: localStorage if web, AsyncStorage if react-native
import { AsyncStorage } from 'react-native';
const persistConfig = {
key: 'root',
storage
};
const rootReducer = persistCombineReducers(persistConfig, {
user: userReducer
});
const persistedReducer = persistReducer(persistConfig, rootReducer);
export default () => {
let store = createStore(persistedReducer)
let persistor = persistStore(store, {storage: AsyncStorage})
return { store, persistor };
}
You are exporting a function from configureStore.js but trying to import {persistor, store} in index.js.
You should import the function instead and call it.
For example:
import configureStore from './store/configureStore';
const {store, persistor} = configureStore();
import thunk from "redux-thunk";
import { persistStore, persistReducer } from "redux-persist";
import { AsyncStorage } from "react-native";
import logger from "redux-logger";
const persistConfig = {
key: "root",
storage: AsyncStorage,
whitelist: ["authReducer"],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const middleWares = [thunk, logger];
const store = createStore(persistedReducer, applyMiddleware(...middleWares));
let persistor = persistStore(store);
export default { store, persistor };
I was getting the same error "undefined is not an object (evaluating 'store.getState')"
My issue was solved after I removed the default keyword after export
export { store, persistor };