Reputation: 3550
it's a react-native app (redux-pattern) using redux-persist, to persist the data for time when user doesn't have internet connection.
Problem is only part of the data is being persisted. See the screenshot bellow. auth
is persisted and loaded from AsyncStorage
without any problems. but others courses
, evaluations
, ... are persisted partly.
for example courses/courses includes the userId of 1, but it's an empty object.
****UPDATE new screenshot, auto-rehydrate with logs on:
Store.js :
import { persistStore, autoRehydrate } from "redux-persist";
import { applyMiddleware, createStore, compose } from "redux";
import { AsyncStorage } from "react-native";
import thunk from "redux-thunk";
import createLogger from "redux-logger";
import rootReducer from "./rootReducer";
const logger = createLogger();
const store = createStore(rootReducer, compose(
applyMiddleware(thunk, logger),
autoRehydrate()
));
persistStore(store, {storage: AsyncStorage});
export default store;
auth.reducer.js
import * as types from "./auth.actions";
export const INITIAL_STATE = {
token: null,
users: {}
};
export default function auth(state = INITIAL_STATE, action) {
const {users, token} = state;
switch (action.type) {
case types.AUTH_LOGIN:
users[action.payload.userId] = {
token: action.payload.token,
///.... continues
};
return Object.assign({}, state, {
loading: false,
token: action.payload.token,
user: action.payload.userId,
users: users
});
case types.AUTH_LOGIN_FAILED:
return Object.assign({}, state, {
users,
token
});
case types.AUTH_LOGOUT:
return Object.assign({}, state, {
token: "",
user: "",
users: {}
});
default:
return state;
}
}
There are few more components, for example see the codes for Courses :
courses.reducer.js
import * as types from "./courses.actions";
export const INITIAL_STATE = {
courses: {}
};
export default function courses(state = INITIAL_STATE, action){
const {courses, lectures, schedule, events, discussion} = state;
switch(action.type){
case types.GET_COURSES:
return Object.assign({}, state, {
courses: action.payload.courses,
lectures: action.payload.lectures,
schedule: action.payload.schedule,
events: action.payload.events,
discussion: action.payload.discussion
});
case types.GET_COURSES_FAILED:
return state;
case types.BOOK_COURSE:
return state;
case types.UNBOOK_COURSE:
return state;
case types.BOOK_COURSE_FAILED:
return state;
case types.UNBOOK_COURSE_FAILED:
return state;
default:
return state;
}
}
Any solutions please?
*** UPDATE (requested by petsome) courses.actions.js
export const GET_COURSES = 'GET_COURSES';
export const GET_COURSES_FAILED = 'GET_COURSES_FAILED';
export const BOOK_COURSE = 'BOOK_COURSE';
export const UNBOOK_COURSE = 'UNBOOK_COURSE';
export const BOOK_COURSE_FAILED = 'BOOK_COURSE_FAILED';
export const UNBOOK_COURSE_FAILED = 'UNBOOK_COURSE_FAILED';
import Functions from '../common/Functions';
export const getCourses = (users) => {
return dispatch => {
Functions.getCoursesAPI(users)
.then((data)=>{
const {courseList, lectureList, schedule, eventList, discussion, coursesArray} = data;
return dispatch(coursesSuccess(courseList, lectureList, schedule, eventList, discussion, coursesArray));
//return dispatch(coursesFailed('e'));
})
.catch((e)=>{
return dispatch(coursesFailed(e));
});
};
};
export const bookCourse = (user, courseId, callback) => {
return dispatch => {
Functions.bookCourse(user, courseId, callback)
.then((data)=>{
return dispatch(bookCourseSuccess(data));
})
.catch((e)=>{
return dispatch(bookCourseSuccessFailed(e));
});
};
};
export const unbookCourse = (user, courseId, callback) => {
return dispatch => {
Functions.unbookCourse(user, courseId, callback)
.then((data)=>{
return dispatch(unbookCourseSuccess(data));
})
.catch((e)=>{
return dispatch(unbookCourseSuccessFailed(e));
});
};
};
const coursesSuccess = (courses, lectures, schedule, eventList, discussion, coursesArray) => {
return {
type: GET_COURSES,
payload: {
courses: courses,
lectures: lectures,
schedule: schedule,
events: eventList,
discussion: discussion,
coursesArray: coursesArray
}
}
};
const coursesFailed = (e) => {
return {
type: GET_COURSES_FAILED,
payload: {
error: e
}
}
};
const unbookCourseSuccess = (data) => {
return {
type: UNBOOK_COURSE,
payload: {
data: data
}
};
};
const unbookCourseSuccessFailed = (e) => {
return {
type: UNBOOK_COURSE_FAILED,
payload: {
error: e
}
};
};
const bookCourseSuccess = (data) => {
return {
type: BOOK_COURSE,
payload: {
data: data
}
};
};
const bookCourseSuccessFailed = (e) => {
return {
type: BOOK_COURSE_FAILED,
payload: {
error: e
}
};
};
Upvotes: 1
Views: 3024
Reputation: 8057
i'm not sure if:
return Object.assign({}, state, {
loading: false,
token: action.payload.token,
user: action.payload.userId,
users: users
});
Be the best option.
In my experience to keep your reducer up to date, you must use ...state
case YOUR_NAME_CASE:
return {
...state,
//Your keys for update
}
Upvotes: 1
Reputation: 49
From my own experience, I would advice that you add a timestamp in your redux store to indicate when the data was persisted. So that when the client tries to fetch new data from the server, it can request for the timestamp from the server to compare with clients' before updating the redux store. There can be inconsistency with syncing the persisted data on the client and the one coming from the server.
Upvotes: 1