React Native with async Redux state - react-native

I have a React Native app and using Redux Toolkit to store application state. It should load state from remote server during init process.
import { configureStore } from '#reduxjs/toolkit'
import counterReducer, {setAmount} from '../reducers/counterSlice';
import tankReducer, {DEFAULT_TANK} from '../reducers/tankSlice';
import logger from 'redux-logger'
import thunk from 'redux-thunk';
const preloadedState = {
counter:
{
value: 500
},
tank:
{
currentTank: DEFAULT_TANK,
tankList: [DEFAULT_TANK]
}
}
export const store = configureStore({
reducer: {
counter: counterReducer,
tank: tankReducer
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger, thunk),
preloadedState
})
It works fine with static, but i need get that preloadedState from the server with async request. How to do it? I mean can I somehow force configureStore logic to wait until I get async data from the server? Or where I can put async code which update state immediately after I do configureStore?

Related

react-redux useSelector() hook not working

I am new to React Native Programming. So, please tell me in detail. thank you.
calling use Selector
I am calling use Selector inside my functional component like this:
import { useDispatch, useSelector } from 'react-redux';
const AddAddressScreen = ({ navigation }) => {
const dispatch = useDispatch();
const data = useSelector(state => state);
console.log(data + "happy Coding");
return (
<View style={styles.container}>
<View>
);
}
export default AddAddressScreen;
My reducer looks like this
case types.API_LOGIN_SUCCESS:
if (action.result.result.mobile_verified === false) {
return {
...state,
onLoad: false,
result: action.result,
status: action.status,
error: null,
navigation: action.navigation.navigate("VerifyMNO")
};
} else {
return {
...state,
onLoad: false,
result: action.result,
status: action.status,
error: null,
navigation: action.navigation.navigate("AddAddress")
};
}
here my mobile number is verified so I move to the address screen.
where I use Use Selector which gives me an error. while I remove above two lines my code runs successfully.
My saga looks like this
export function* watchLoginUserInfo() {
yield takeLatest(types.LOGIN_USER, loginApiSaga)
}
My root saga
import { all, fork } from 'redux-saga/effects';
import { watchLoginUserInfo, } from './authenticationSagas';
function* rootSaga() {
yield all([
watchLoginUserInfo(),
])
}
export default rootSaga;
My Store looks like this
import {createStore, applyMiddleware} from 'redux';
import rootReducer from '../redux/reducers/root-reducer.js'
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../redux/sagas/rootSaga';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
export {store};
when ever I use use Selector hook in my code it gives me the following error.
error 1
error 2, 3, 4
Use the select effect from redux-saga inside of a reducer: https://redux-saga.js.org/docs/api/#selectselector-args
For example const selectedState = yield select(state => state);.
The useSelector hook is for use inside of a function component.
EDIT: since the above doesn't seem to be the issue, I think the issue is that you're calling navigation functions from within your reducer. Reducer code can have no side effects, so you can't call navigation.navigate(...) from within the reducer. This will need to happen in the saga code instead. It might be able to be done in the loginApiSaga or in a dedicated saga that is triggered by API_LOGIN_SUCCESS.

Theory: Axios Calls (Specifically for VueJS)

On component mount(), Axios fetches information from the back end. On a production site, where the user is going back and forth between routes it would be inefficient to make the same call again and again when the data is already in state.
How do the pros design their VueJS apps so that unnecessary Axios calls are not made?
Thank you,
If the data is central to your application and being stored in Vuex (assuming that's what you mean by "state"), why not just load it where you initialise your store?
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'wherever'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
centralData: {}
},
mutations: {
setCentralData (state, centralData) {
state.centralData = centralData
}
},
actions: {
async loadCentralData ({ commit }) {
const { data } = await axios.get('/backend')
commit('setCentralData', data)
}
}
}
// initialise
export const init = store.dispatch('loadCentralData')
export default store
If you need to wait for the dispatch to complete before (for example) mounting your root Vue instance, you can use the init promise
import Vue from 'vue'
import router from 'path/to/router'
import store, { init } from 'path/to/store'
init.then(() => {
new Vue({
store,
router,
// etc
}).$mount('#app')
})
You can import and use the init promise anywhere in order to wait for the data to load.

redux-persist/createPersistoid: error serializing state TypeError: Converting circular structure to JSON

I am trying to integrate redux-persist to my react-native project. The aim is to persist the redux store's data between application re-launch so that user does not need to log in each time they launch the app. Also, I want to store the previously viewed data on the local storage to avoid re-querying all the data each time app is re-launched.
I added the redux persist support as per the code below:
import { AsyncStorage } from 'react-native';
import { createStore, applyMiddleware } from 'redux';
//import { createLogger } from 'redux-logger';
import { persistStore, persistReducer } from 'redux-persist';
import rootReducer from '../reducers/index';
import ReduxThunk from 'redux-thunk';
import { createTransform } from 'redux-persist';
import JSOG from 'jsog';
export const JSOGTransform = createTransform(
(inboundState, key) => JSOG.encode(inboundState),
(outboundState, key) => JSOG.decode(outboundState),
)
const persistConfig = {
// Root
key: 'root',
// Storage Method (React Native)
storage: AsyncStorage,
//transforms: [JSOGTransform]
// Whitelist (Save Specific Reducers)
// whitelist: [
// 'authReducer',
// ],
// // Blacklist (Don't Save Specific Reducers)
// blacklist: [
// 'counterReducer',
// ],
};
// Middleware: Redux Persist Persisted Reducer
const persistedReducer = persistReducer(persistConfig, rootReducer);
// Redux: Store
const store = createStore(
persistedReducer,
applyMiddleware(ReduxThunk),
);
// Middleware: Redux Persist Persister
let persistor = persistStore(store);
// Exports
export {
store,
persistor,
};
If I don't add jsog and use the transforms: [JSOGTransform] line in the persistConfig I get this error:
redux-persist/createPersistoid: error serializing state TypeError:
Converting circular structure to JSON
If I uncomment the 'transforms' line in the persistConfig (as per the suggestion here: https://github.com/rt2zz/redux-persist/issues/735), then I get this error:
Exception in HostObject::set: < unknown >
I am just persisting the returned "user" object from the firestore database in my redux-store. Without the redux-persist, there has been no problem, but with the persist added I am having this issue.
What type of circular problem would exist in the user object returned after successful login to firestore (using password/email auth.)?
Why would JSOG not work as suggested in the link above? Any alternatives to how I can solve this problem?
P.S. Not only the user returned from firestore is causing these errors, but any data returned from firestore seems to fail to persist.
I appreciate any helps!
Cheers...
I think I solved the problem. Instead of JSOG I installed flatted and used in for my redux-persist transform.
Working transform and persistConfig looks like this:
export const transformCircular = createTransform(
(inboundState, key) => Flatted.stringify(inboundState),
(outboundState, key) => Flatted.parse(outboundState),
)
const persistConfig = {
key: 'root',
storage: AsyncStorage,
stateReconciler: autoMergeLevel2,
transforms: [transformCircular]
};
Some developer have this problem because of the socket set in Redax, Otherwise, you can use this way as well
// SetTransform.js
import { createTransform } from 'redux-persist';
const SetTransform = createTransform(
// transform state on its way to being serialized and persisted.
(inboundState, key) => {
// convert mySet to an Array.
return { ...inboundState, mySet: [...inboundState.mySet] };
},
// transform state being rehydrated
(outboundState, key) => {
// convert mySet back to a Set.
return { ...outboundState, mySet: new Set(outboundState.mySet) };
},
// define which reducers this transform gets called for.
{ whitelist: ['someReducer'] }
);
export default SetTransform;
and
// PersistReducers
import storage from 'redux-persist/lib/storage';
import { SetTransform } from './transforms';
const persistConfig = {
key: 'root',
storage: storage,
transforms: [SetTransform]
};

Got An Error: firestore.setListeners is not a function. while integrating redux-firestore with react-redux-firebase#2.0.*

Blockquote
PHOTO(Click here to see the Error) : Got An Error: firestore.setListeners is not a function
Blockquote
I have just integrated redux-saga, redux-firestore with react-redux-firebase#2.. and its working fine but when i try to integrate with other COMPONENT i got This Error..
ANY SOLUTION!!
THANKS
This is the error white integrating redux-firestore with react-reduc-firebase
Code:
import { compose } from 'redux'
import { connect } from 'react-redux'
// import { getFirestore } from 'redux-firestore';
import {
firestoreConnect,
createWithFirebase,
withFirebase,
firebaseConnect
} from 'react-redux-firebase'
*******
**etc**
*******
// export default Inventory;
export default compose(
// firestoreConnect([{collection: 'Invetory'}]),
firebaseConnect(),
connect(
({ firestore }) => ({
//todos: firestore.ordered.todos,
firestore
})
)
// connect((state) => ({
// auth: state.firestore.auth
// })
)(Inventory)
Author of react-redux-firebase here.
Looks like you may not have included importing Firestore as mentioned in the Firestore section of the react-redux-firebase docs. Make sure you include the enhancer, the reducer, and import firestore from Firebase like so:
import { createStore, combineReducers, compose } from 'redux'
import firebase from 'firebase'
import 'firebase/firestore' // add this to use Firestore
import { reactReduxFirebase, firebaseReducer } from 'react-redux-firebase'
import { reduxFirestore, firestoreReducer } from 'redux-firestore'
const firebaseConfig = {}
// react-redux-firebase config
const rrfConfig = {
userProfile: 'users',
// useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
}
// initialize firebase instance
firebase.initializeApp(firebaseConfig) // <- new to v2.*.*
// initialize Firestore
firebase.firestore()
// Add reduxReduxFirebase and reduxFirestore enhancers when making store creator
const createStoreWithFirebase = compose(
reactReduxFirebase(firebase, rrfConfig),
reduxFirestore(firebase)
)(createStore)
// Add Firebase and Firestore to reducers
const rootReducer = combineReducers({
firebase: firebaseStateReducer,
firestore: firestoreReducer
})
// Create store with reducers and initial state
const initialState = {}
const store = createStoreWithFirebase(rootReducer, initialState)

Can not read property length of undefined in React-Native/VirtualizedSectionList.js

I was trying to modify the state of my react-native app; however, after the modification I get the following error message.
Error Message
I have stack traced it to line 230 in the VirtualizedSectionList of react native. I am not sure what exactly would be causing the error. A potential solution may be resetting my react-native store, but I could not figure out how to do that. Here is my current redux store code.
'use strict';
import {applyMiddleware, createStore} from 'redux';
import thunk from 'redux-thunk';
import {persistStore, autoRehydrate} from 'redux-persist';
import {AsyncStorage} from 'react-native';
import reducers from '../reducers';
const logger = store => next => action => {
if(typeof action === 'function') console.log('dispatching a function');
else console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
}
let middlewares = [
logger,
thunk
];
let createAppStore = applyMiddleware(...middlewares)(createStore);
export default function configureStore(onComplete: ()=>void){
const store = autoRehydrate()(createAppStore)(reducers);
let opt = {
storage: AsyncStorage,
transform: [],
blacklist: ['nav','util']
};
persistStore(store, opt, onComplete);
return store;
}
Thanks
This doesn't seem an issue with store, i think it is there where you are using ur states may be or something else, if you upload other code than i can check it but i don't think this error is due to store.