reactjs - Expo、Redux Toolkit、为用户切片数据( session )设置超时

标签 reactjs redux redux-toolkit

我正在将 Redux Toolkit 用于 Expo 应用程序。在这个应用程序中,我有一个 user.js,它是一个 redux 工具包切片。该切片包含身份验证信息(用户数据、访问 token 、刷新 token )。问题是服务器上的 session 会在 15 分钟后过期。

我的客户要求在 15 分钟后从应用程序中注销用户。

我的问题是:如何在 redux 工具包切片中实现此目的?一种方法可以是向我的状态添加一个logging_at时间戳,并且对于每个API请求,检查耗时(比较logged_at>现在),但我想让它以正确的方式进行,我觉得这种方法不是很 Eloquent 或可用。

如何使用 redux/redux 工具包在 X 时间过去后调度一个操作来注销用户?

最佳答案

简单方法:选择器

存储时间戳对我来说听起来不错。我可能更喜欢存储过期时间戳 expiresAt 而不是 loggedAt

您可以在选择器函数中添加一些逻辑,从而无需显式“注销”操作。我们可以将过期的用户保留在状态中,但在访问之前对其进行验证。该函数仅在用户对象仍然有效时返回该用户对象,如果该对象已过期则返回 null。

const selectUser = (state) => Date.now() > state.user.expiresAt ? null : state.user.user;

预定发货

您可以使用 setTimeout 安排调度,但您必须在应用的最高级别执行此操作,而不是在调度的组件中进行 登录。我创建了a little demo 10 秒后自动注销。 useEffect Hook 检测状态中 isLoggedIn 属性的更改(可以通过选择器派生),并在 isLoggedIn 变为 时安排注销正确

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 安排注销以响应登录。您想要创建一个非阻塞 forkdelay 15分钟。通过 saga,您还可以 cancel如果用户在时间到之前自行注销,则任务。

它类似于 this example用于重试使用 2000 毫秒延迟的 API 调用。


异步重击

我们可以使用createAsyncThunk来安排调度有很长的延迟。在解决此问题之前,用户可能已经注销,并且可能有其他用户登录。您可以通过在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;

Code Sandbox Demo

关于reactjs - Expo、Redux Toolkit、为用户切片数据( session )设置超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67023927/

相关文章:

reactjs - 样式组件语义套件(表单.输入)

reactjs - 我如何在 React 中的两个状态之间设置动画并在转换期间查看两个状态

javascript - 如何编写类似于 Redux 的状态更改例程?

javascript - 在代码沙箱中使用 npm 包对 Web Worker 使用react

javascript - 有没有办法将对象而不是数组发送到后端? -ReactJS

javascript - 如何删除最后一个数组映射的分隔符图标?

reactjs - 在React应用程序中接收 "Attempted import error:"

redux-toolkit - Redux 工具包 : Have two slices reference each other's actions in extraReducers?

javascript - 我们如何根据表列对 createEntityAdapter 的实体进行排序?