Why am I getting "redux-persist/createPersistoid: error serializing state"? - react-native

I have no idea why I'm getting this error. there's no file referenced no line referenced. I only know the action thats executed which results in the error.
The full error:
console.error "redux-persist/createPersistoid: error serializing
state", TypeError: JSON.stringify cannot serialize cyclic structures.
Here is the action that causes the error:
export const loadInitialDiscover = () => {
return (dispatch) => {
dispatch({ type: types.DISCOVER_LOADING });
return getNewest(dispatch);
};
};
const getNewest = (dispatch) => {
return firebase
.firestore()
.collection('users')
.where('role', '==', 'a')
.where('active', '==', true)
.orderBy('createdAt')
.limit(10)
.get()
.then((querySnapshot) => {
const newest = [];
querySnapshot.forEach((queryDocSnapshot) => {
const profile = queryDocSnapshot.data();
newest.push(profile);
});
dispatch({ type: types.LOAD_NEWEST, payload: newest });
})
.catch((err) => loadFail(dispatch, err.message));
};
implementation of action in screen:
componentDidMount () {
//console.log('INITIAL REDUX STATE: ' + JSON.stringify(this.props.newest));
this.props.newest == null ? this.props.loadInitialDiscover() : null;
}
notice this .stringify() is commented out
Ive removed literally any and every existing JSON.stringify, deleted build folder, restarted bundler, restarted simulator. the error persists.
here is relevant reducer:
const INITIAL_STATE = {
newest: null,
loading: false,
error: ''
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case types.DISCOVER_LOADING:
return {
...state,
loading: true,
error: ''
};
case types.LOAD_FAIL:
return {
...state,
loading: false,
error: action.info
};
case types.LOAD_NEWEST:
return {
...state,
loading: false,
error: '',
newest: action.payload
};
}
}
and here's the persist config:
const persistAuthConfig = {
key: 'auth',
storage: AsyncStorage
};
const persistUserConfig = {
key: 'user',
storage: AsyncStorage
};
const persistDiscoverConfig = {
key: 'discover',
storage: AsyncStorage
};
const AppReducer = combineReducers({
auth: persistReducer(persistAuthConfig, AuthReducer),
user: persistReducer(persistUserConfig, UserReducer),
discover: persistReducer(persistDiscoverConfig, DiscoverReducer)
});
export default AppReducer;
How do I get this error gone?

The Firestore query response contains cyclic data (ref parameter) that is not possible to serialised by JSON.stringify hence the error from Redux-Persist, (yes; redux-persist use it under the hood). Just remove the ref parameter containing the cyclic data from all the objects inserted into the array newest array.
Also, do a check on other parameters that cannot be serialised by JSON.stringify like ref.
The below may help you to achieve this:-
const newest = []; querySnapshot.forEach((queryDocSnapshot) => {
const profile = queryDocSnapshot.data();
const {ref, ...profileSerialisable} = profile;
newest.push(profileSerialisable);
});
Please refer here for more discussions based on this.

Related

react-native-storage returning undefined from local storage

I am having some difficulties on executing local storage operations...
"react-native": "0.64",
"react-native-storage": "^1.0.1"
I'm using react-native-storage, as pointed in title, and I have created two simple methods for handling Writing and Reading:
import Storage from 'react-native-storage';
import AsyncStorage from '#react-native-community/async-storage';
const storage = new Storage({
size: 1000,
storageBackend: AsyncStorage,
defaultExpires: null,
enableCache: true,
sync: {
return: 'No data.'
}
});
const saveToLocalStorage = (key: any, data: any) => {
storage.save({
key,
data,
expires: null
})
}
const getFromLocalStorage = (key: any) => {
storage.load({
key,
autoSync: true
})
.then(data => {
return { data }
})
.catch(err => { });
}
export { saveToLocalStorage, getFromLocalStorage }
As you can see, it's pretty much the code example from https://www.npmjs.com/package/react-native-permissions.
At the App.tsx file, I do the following:
useEffect(() => {
saveToLocalStorage('test', 'test data');
const test = getFromLocalStorage('test');
}, [])
which returns undefined.
But if in the method getFromLocalStorage I replace
.then(data => {
return { data }
})
for
.then(data => console.warn(data));
the result is the image from bellow:
In short:
If the function returns the object from the storage, it brings undefined.
If the function returns a console.log from the storage, it brings what I've written on it.
because return { data } is not a valid expression for async functions
just use AsyncStorage, react-native-storage is not needed unless you develop for both mobile and web
useEffect(() => {
await AsyncStorage.setItem('test', 'myValue');
const value = await AsyncStorage.getItem('test');
console.log(value);
}, [])

ngrx store state undefined

I am not sure why my state in my store is undefined when I try to access it. I have been looking at this for sometime now and I cannot figure it out.
my actions are
export const GetMerchants = createAction('[Merchant] - Get Merchants');
export const GetMerchantsSuccess = createAction(
'[Merchant] - Get Merchants Success',
props<{ payload: Merchant[] }>()
);
export const GetMerchantsFailure = createAction(
'[Merchant] - Get Merchants Failure',
props<{ payload: Error }>()
);
My reducers and state def are
export default class MerchantListState {
merchants: Array<Merchant>;
merchantError: Error;
}
export const initializeMerchantListState = (): MerchantListState => {
return {
merchants: new Array<Merchant>(),
merchantError: null
};
};
export const intialMerchantListState = initializeMerchantListState();
const _reducer = createReducer(
intialMerchantListState,
on(actions.GetMerchants, (state: MerchantListState) => {
return {
...state
};
}),
on(actions.GetMerchantsSuccess, (state: MerchantListState, { payload }) => {
let newstate = { ...state,
merchants: [ ...state.merchants, payload],
merchantError: null
};
return newstate;
}),
on(actions.GetMerchantsFailure, (state: MerchantListState, { payload }) => {
console.log(payload);
return { ...state, merchantError: payload };
}),
);
export function merchantListReducer(state: MerchantListState, action: Action) {
return _reducer(state, action);
}
My effects
#Injectable()
export class MerchantListEffects {
constructor(private apiService: ApiService, private apiRouteService: ApiRouteService, private action$: Actions) { }
GetMerchants$: Observable<Action> = createEffect(() =>
this.action$.pipe(
ofType(actions.GetMerchants),
mergeMap(action => this.apiService.get(this.apiRouteService.toMerchants()).pipe(
map((data: Merchant[]) => { console.log(data); return actions.GetMerchantsSuccess({ payload: data }); }
), catchError((error: Error) => { return of(actions.GetMerchantsFailure({ payload: error })) })
)
)));
}
When I inject the state into the component
private store: Store<{ merchantList: MerchantListState }>
I get an undefined merchant$ observable when I try to do this
this.merchants$ = store.pipe(select('merchantList'));
this.merchantSubscription = this.merchants$.pipe(
map(x => {
console.log(x.merchants);
})
)
.subscribe();
On a button click I am loading the merchants with this dispatch
this.store.dispatch(actions.GetMerchants());
I have my reducer and effects defined in AppModule
StoreModule.forRoot({ merchantList: merchantListReducer }),
EffectsModule.forRoot([MerchantListEffects])
Is it something that I am missing?
First Parameter of createReducer is a value, not a function.
API > #ngrx/store
createReducer
If you use a function, you have to call it:
const _reducer = createReducer(
intialMerchantListState()
I prefare the way to define direct a value initialState:
export const initializeMerchantListState: MerchantListState = {
merchants: new Array<Merchant>(),
merchantError: null
};

NgRX 8 is not working in my Angular 8 with a failure: 'toJSON failed on Type'

I have been trying since yesterday to add the new NgRX 8 to my Angular application. But I am stuck on one thing and I don't know what the problem is.
I have tried to build a very simple example for movies:
export class Movie {
public id: number;
public name: string;
constructor() {}
}
My actions are:
export const getAll = createAction('[Movies Page] Load Movies');
export const getAllSuccess = createAction('[Movies Page] Load Movies Success', props<{ payload: Movie[] }>());
export const getAllFail = createAction('[Movies Page] Load Movies Fail', props<{ error: any }>());
And my effect is:
#Injectable()
export class MovieEffects {
constructor(private actions$: Actions) {
}
loadMovies$ = createEffect(() =>
this.actions$.pipe(
ofType(getAll),
switchMap(() =>
of([movies_array]).pipe(
map(result => getAllSuccess({ payload: result })),
catchError(error => of(getAllFail({ error })))
)
)
)
);
}
I have added all of action cases to my reducer:
export interface AppState<T> {
list: T[];
isNull: boolean;
count: number;
type: StateType;
}
export const initialState: AppState<Movie> = {
type: StateType.Loading,
isNull: true,
count: 0,
list: new Array<Movie>()
};
const movieRed = createReducer(
initialState,
on(MovieActionTypes.getAll, state => ({
...state,
type: StateType.Loading
})),
on(MovieActionTypes.getAllSuccess, (state: AppState<Movie>, action) => ({
...state,
type: StateType.Loaded,
isNull: action.payload == null,
count: action.payload != null ? action.payload.length : 0,
list: action.payload
})),
on(MovieActionTypes.getAllFail, state => ({
...state,
type: StateType.Error
}))
);
export function movieReducer(state: AppState<Movie> = initialState, action) {
return movieRed(state, action);
}
And added the effects forRoot and reducers forRoot in my module.
Everything works fine. But when I am trying to read the state using:
this.movies$ = store.pipe(select('list'));
I result is always undefined and I see this message in my DevTool
I have no idea where the problem is. I have tried many solutions, none has worked for me.
Does anybody know why and how to fix it?
I have found the answer. I have missed defining the AppState.
export interface AppState {
movieReducer: ReducerState<Movie>;
}
and in the module:
StoreModule.forFeature('movieReducer', movieReducer),

useMutation not mutating the local state

I'm getting this error while trying to mutate the local state in apollo.
errInvariant Violation: Expecting a parsed GraphQL document. Perhaps you need to wrap the query string in a "gql" tag? http://docs.apollostack.com/apollo-client/core.html#gql
Initial state
registration: {
__typename: 'Registration',
tempMerchantId: '',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
nid_front: '',
nid_back: '',
authorized_person_photo: ''
}
}
My mutation
export const setAuthorizePersonQuery = gql`
mutation setAuthorizePersonProfileInfo($authorizePerosnData: Object!){
setAuthorizePersonProfileInfo(authorizePersonData: $authorizePerosnData) #client
}
`;
My resolver
export const setAuthorizePersonProfileInfo = (
_, { authorizePersonData }, { cache }
) => {
try {
const prevData = cache.readQuery({ getAuthorizePersonProfileQuery });
cache.writeQuery({
getAuthorizePersonProfileQuery,
data: {
registration: {
__typename: 'Registration',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
...prevData.registration.authorizeProfile,
...authorizePersonData
}
}
}
});
} catch (e) {
console.log(`err${e}`);
}
return null;
};
I'm trying to mutate the local state on button press, the function is
const handlePressedNext = () => {
Promise.all([
setAuthorizePersonProfileInfo({
variables: { authorizePersonData: generateNidData() }
})
])
.then(() => {
navigation.navigate('Photograph');
});
};
generateNidData function is like bellow
const generateNidData = () => ({
nid_front: nidFrontImage,
nid_back: nidBackImage
});
I'm new to apollo client. I can not understand what I'm doing wrong. Can anyone help me figure out the problem?
getAuthorizePersonProfileQuery is not a valid option for readQuery. Presumably, you meant use query instead.

Unable to get payload from action in reducer inside react native app?

I am trying to get a json response from an api and get the data successfully but when I call a action within another action using redux-thunk, my data is not available inside the reducer. I need data in "data" property inside my reducer get in component. Check the code below.
This is my action
import { GET_REPORT, GET_DATA_SUCCESS } from './types';
export const getData = (text) => {
return (dispatch) => {
dispatch ({ type: GET_REPORT})
fetch('http://api.openweathermap.org/data/2.5/forecast?q='+text+'&cnt=1&units=metric&APPID={key}')
.then(response => response.json())
.then(data => getDataSuccess(dispatch, data.list[0]))
.catch((error) => console.log(error));
};
};
const getDataSuccess = (dispatch, data) => {
//console.log(data);
dispatch({
type: GET_DATA_SUCCESS,
payload: data
});
}
this is my reducer
import { GET_REPORT } from'../actions/types';
const INITIAL_STATE = {
data: '',
}
export default (state = INITIAL_STATE, action) => {
switch(action.type){
case GET_REPORT:
console.log(action.payload); // getting undefined
return {...state, data: action.payload};
default:
return state;
}
}
I need data in "data" property get in component.
you are missing GET_DATA_SUCCESS in your reducer
The action dispatch ({ type: GET_REPORT}) , doesn't contain a payload hence undefined. Either you need to make reducer to handle action GET_DATA_SUCCESS or modify the existing one.
To simplify, dispatch({
type: GET_DATA_SUCCESS,
payload: data
}); contains a payload whereas dispatch ({ type: GET_REPORT}) doesn't
Resolved it by adding new switch case for GET_DATA_SUCCESS and get the payload from getDataSuccess and removing the payload from GET_REPORT case.
Now switch case looks like this
switch(action.type){
case GET_REPORT:
return {...state};
case GET_DATA_SUCCESS:
console.log(action.payload);
return{...state, data: action.payload}
default:
return state;
}