Ata Mohammadi
Ata Mohammadi

Reputation: 3550

React Redux + redux persist : only part of the data persists

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.

enter image description here

****UPDATE new screenshot, auto-rehydrate with logs on: enter image description here 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

Answers (2)

jose920405
jose920405

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

Petsome
Petsome

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

Related Questions