React Redux + redux persist : 只有部分数据持久化
React Redux + redux persist : only part of the data persists
这是一个使用 redux-persist 的 react-native 应用程序(redux 模式),用于在用户没有互联网连接时持久保存数据。
问题是只有部分数据被持久化了。请参阅下面的屏幕截图。 auth
被保留并从 AsyncStorage
加载,没有任何问题。但其他 courses
, evaluations
, ... 部分保留。
例如 courses/courses 包含用户 ID 1,但它是一个空对象。
****更新新截图,登录后自动补水:
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;
}
}
还有一些组件,例如参见课程代码:
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;
}
}
有什么解决办法吗?
*** 更新(由 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
}
};
};
根据我自己的经验,我建议您在 redux 存储中添加时间戳以指示数据何时持久化。这样当客户端尝试从服务器获取新数据时,它可以在更新 redux 存储之前向服务器请求时间戳以与客户端进行比较。同步客户端上的持久数据和来自服务器的数据可能会不一致。
我不确定是否:
return Object.assign({}, state, {
loading: false,
token: action.payload.token,
user: action.payload.userId,
users: users
});
成为最佳选择。
根据我的经验,要让你的减速器保持最新状态,你必须使用 ...state
case YOUR_NAME_CASE:
return {
...state,
//Your keys for update
}
这是一个使用 redux-persist 的 react-native 应用程序(redux 模式),用于在用户没有互联网连接时持久保存数据。
问题是只有部分数据被持久化了。请参阅下面的屏幕截图。 auth
被保留并从 AsyncStorage
加载,没有任何问题。但其他 courses
, evaluations
, ... 部分保留。
例如 courses/courses 包含用户 ID 1,但它是一个空对象。
****更新新截图,登录后自动补水:
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;
}
}
还有一些组件,例如参见课程代码:
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;
}
}
有什么解决办法吗?
*** 更新(由 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
}
};
};
根据我自己的经验,我建议您在 redux 存储中添加时间戳以指示数据何时持久化。这样当客户端尝试从服务器获取新数据时,它可以在更新 redux 存储之前向服务器请求时间戳以与客户端进行比较。同步客户端上的持久数据和来自服务器的数据可能会不一致。
我不确定是否:
return Object.assign({}, state, {
loading: false,
token: action.payload.token,
user: action.payload.userId,
users: users
});
成为最佳选择。
根据我的经验,要让你的减速器保持最新状态,你必须使用 ...state
case YOUR_NAME_CASE:
return {
...state,
//Your keys for update
}