Expo,Redux Toolkit,为用户切片数据设置超时时间(session)
Expo, Redux Toolkit, set timeout for user slice data (session)
我正在为 Expo 应用程序使用 Redux Toolkit。在这个应用程序中,我有一个 user.js,它是一个 redux 工具包切片。此切片具有身份验证信息(用户数据、访问令牌、刷新令牌)。问题是服务器上的会话在 15 分钟后过期。
我的客户要求在 15 分钟后从应用程序注销用户。
我的问题是:如何在 redux 工具包切片中实现这一点?一种方法是在我的状态中添加一个 logged_at 时间戳,并且对于每个 API 请求,检查经过的时间(比较 logged_at > 现在),但我想让它成为正确的方式,我感觉这种方法不是很eloquent或可用。
如何在 X 时间过去后使用 redux/redux 工具包发送一个操作来注销用户?
简单方法:选择器
我觉得存储时间戳很合适。我可能更愿意存储过期时间戳 expiresAt
而不是 loggedAt
.
您可以在选择器函数中添加一些逻辑,从而消除对显式“注销”操作的需要。我们可以将过期用户保留在状态中,但在访问之前对其进行验证。此函数仅 returns 用户对象(如果它仍然有效)和 null
如果它已经过期。
const selectUser = (state) => Date.now() > state.user.expiresAt ? null : state.user.user;
计划派送
您可以使用 setTimeout
安排 dispatch
,但您必须在应用程序的最高级别而不是在您 dispatch
登录的组件中执行此操作。我创建了 a little demo,它会在 10 秒后自动注销。 useEffect
挂钩从状态(可以通过选择器派生)检测到 isLoggedIn
属性 的更改,并在 isLoggedIn
变为 true
时安排注销。
const App = () => {
const isLoggedIn = useSelector((state) => state.user.isLoggedIn);
const dispatch = useDispatch();
useEffect(
() => {
if (isLoggedIn) {
setTimeout(
() => {
dispatch(logOut());
alert("Logged Out");
},
// log out after 10 seconds
10 * 1000
);
}
},
// respond to changes in isLoggedIn
[dispatch, isLoggedIn]
);
return <LogIn />;
};
Redux-Saga
您可以使用 redux-saga 安排注销以响应登录。如果用户在时间结束前自行注销,您可能希望创建一个非阻塞 fork
with a delay
for 15 minutes. With saga you can also cancel
任务。
它类似于 this example 重试 API 使用 2000 毫秒延迟的调用。
异步 Thunk
我们可以使用具有较长延迟的 createAsyncThunk
来安排 dispatch
。用户可能已经注销,而其他用户可能会在此问题解决之前登录。您可以通过在 reducer 或 thunk 中检查用户名与当前用户名来处理此问题。
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
interface User {
username: string;
}
type UserState = User | null;
const initialState = null as UserState;
const wait = (ms: number) =>
new Promise<void>((resolve) => {
setTimeout(() => resolve(), ms);
});
export const asyncLogIn = createAsyncThunk(
"user/asyncLogIn",
async (user: User) => {
await wait(10 * 1000);
return user;
}
);
const userSlice = createSlice({
name: "user",
initialState,
reducers: {
// manual log out
logOut() {
return null;
}
},
extraReducers: (builder) =>
builder
// log in when thunk is initiated
.addCase(asyncLogIn.pending, (state, action) => {
const user = action.meta.arg;
return user;
})
// log out when thunk finally resolves
.addCase(asyncLogIn.fulfilled, (state, action) => {
// only log out if this user is still the logged in user
if (action.payload.username === state?.username) {
return null;
}
})
});
export const { logOut } = userSlice.actions;
export default userSlice.reducer;
我正在为 Expo 应用程序使用 Redux Toolkit。在这个应用程序中,我有一个 user.js,它是一个 redux 工具包切片。此切片具有身份验证信息(用户数据、访问令牌、刷新令牌)。问题是服务器上的会话在 15 分钟后过期。
我的客户要求在 15 分钟后从应用程序注销用户。
我的问题是:如何在 redux 工具包切片中实现这一点?一种方法是在我的状态中添加一个 logged_at 时间戳,并且对于每个 API 请求,检查经过的时间(比较 logged_at > 现在),但我想让它成为正确的方式,我感觉这种方法不是很eloquent或可用。
如何在 X 时间过去后使用 redux/redux 工具包发送一个操作来注销用户?
简单方法:选择器
我觉得存储时间戳很合适。我可能更愿意存储过期时间戳 expiresAt
而不是 loggedAt
.
您可以在选择器函数中添加一些逻辑,从而消除对显式“注销”操作的需要。我们可以将过期用户保留在状态中,但在访问之前对其进行验证。此函数仅 returns 用户对象(如果它仍然有效)和 null
如果它已经过期。
const selectUser = (state) => Date.now() > state.user.expiresAt ? null : state.user.user;
计划派送
您可以使用 setTimeout
安排 dispatch
,但您必须在应用程序的最高级别而不是在您 dispatch
登录的组件中执行此操作。我创建了 a little demo,它会在 10 秒后自动注销。 useEffect
挂钩从状态(可以通过选择器派生)检测到 isLoggedIn
属性 的更改,并在 isLoggedIn
变为 true
时安排注销。
const App = () => {
const isLoggedIn = useSelector((state) => state.user.isLoggedIn);
const dispatch = useDispatch();
useEffect(
() => {
if (isLoggedIn) {
setTimeout(
() => {
dispatch(logOut());
alert("Logged Out");
},
// log out after 10 seconds
10 * 1000
);
}
},
// respond to changes in isLoggedIn
[dispatch, isLoggedIn]
);
return <LogIn />;
};
Redux-Saga
您可以使用 redux-saga 安排注销以响应登录。如果用户在时间结束前自行注销,您可能希望创建一个非阻塞 fork
with a delay
for 15 minutes. With saga you can also cancel
任务。
它类似于 this example 重试 API 使用 2000 毫秒延迟的调用。
异步 Thunk
我们可以使用具有较长延迟的 createAsyncThunk
来安排 dispatch
。用户可能已经注销,而其他用户可能会在此问题解决之前登录。您可以通过在 reducer 或 thunk 中检查用户名与当前用户名来处理此问题。
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
interface User {
username: string;
}
type UserState = User | null;
const initialState = null as UserState;
const wait = (ms: number) =>
new Promise<void>((resolve) => {
setTimeout(() => resolve(), ms);
});
export const asyncLogIn = createAsyncThunk(
"user/asyncLogIn",
async (user: User) => {
await wait(10 * 1000);
return user;
}
);
const userSlice = createSlice({
name: "user",
initialState,
reducers: {
// manual log out
logOut() {
return null;
}
},
extraReducers: (builder) =>
builder
// log in when thunk is initiated
.addCase(asyncLogIn.pending, (state, action) => {
const user = action.meta.arg;
return user;
})
// log out when thunk finally resolves
.addCase(asyncLogIn.fulfilled, (state, action) => {
// only log out if this user is still the logged in user
if (action.payload.username === state?.username) {
return null;
}
})
});
export const { logOut } = userSlice.actions;
export default userSlice.reducer;