【问题标题】:react redux saga does not put actionreact redux saga 没有采取行动
【发布时间】:2021-06-02 11:52:50
【问题描述】:

我正在尝试执行以下操作- 用户可以登录,但 5 秒后会自动注销。 我与 JSONWEBTOKEN 合作。

这是我在 react 中使用 redux sagas 的尝试:

app.ts 文件(存储根目录):

import { applyMiddleware, combineReducers, compose, createStore, Reducer } from 'redux';
import createSagaMiddleware from 'redux-saga';

import * as fromAuth from './reducers/auth';

import { watchAuth } from './sagas/auth';

export interface AppState {
  auth: fromAuth.State;
}

const composeEnhancers: typeof compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const sagaMiddleware = createSagaMiddleware();

const rootReducer: Reducer<AppState> = combineReducers({
  auth: fromAuth.reducer,
});

export const store = createStore(rootReducer, composeEnhancers(applyMiddleware(sagaMiddleware)));

sagaMiddleware.run(watchAuth);

传奇文件:

import { ForkEffect, put, select, takeEvery } from 'redux-saga/effects';

import * as fromApp from '../app';
import * as authActions from '../actions/auth';

// --- Workers (Effects) --- //

function* loginSaga() {
  const logoutTimeoutCreationDate: string | null = yield localStorage.getItem('logoutTimeoutCreationDate');

  let logoutTimeout: number;

  if (
    !logoutTimeoutCreationDate ||
    new Date(logoutTimeoutCreationDate).getTime() + 5000 < new Date().getTime()
  ) {
    yield localStorage.setItem('logoutTimeoutCreationDate', new Date().toISOString());

    logoutTimeout = yield 5000;
  } else {
    logoutTimeout = yield new Date(logoutTimeoutCreationDate).getTime() + 5000 - new Date().getTime();
  }

  const newTimeout: NodeJS.Timeout = yield setTimeout(() => put(authActions.logout()), logoutTimeout);
  yield put(authActions.setLogoutTimeout(newTimeout));
}

function* logoutSaga() {
  const timeout: NodeJS.Timeout = yield select((state: fromApp.AppState) => state.auth.logoutTimeout);

  yield clearTimeout(timeout);
  yield sessionStorage.removeItem('token');
  yield localStorage.removeItem('logoutTimeoutCreationDate');

  yield put(authActions.setLogoutTimeout(null));
}

// --- Watchers --- //

export function* watchAuth():IterableIterator<ForkEffect>{
  yield takeEvery(authActions.AUTH_LOGIN, loginSaga);
  yield takeEvery(authActions.AUTH_LOGOUT, logoutSaga);
}

减速机文件:

import * as actions from '../actions/auth';
import { IUser } from '../../models/user';

export interface State {
  user: IUser | null;
  logoutTimeout: NodeJS.Timeout | null;
}

const initialState: State = {
  user: null,
  logoutTimeout: null,
};

export const reducer = (state: State = initialState, action: actions.AuthTypes): State => {
  switch (action.type) {
    case actions.AUTH_LOGOUT:
      return { ...state, user: null };
    case actions.AUTH_LOGIN:
      return { ...state, user: action.payload.user };
    case actions.AUTH_SET_LOGOUT_TIMEOUT:
      return { ...state, logoutTimeout: action.payload.timeout };
    default:
      return state;
  }
};

动作文件:

import { IUser } from '../../models/user';

export const AUTH_LOGOUT = '[Auth] Logout';
export const AUTH_LOGIN = '[Auth] Login';
export const AUTH_SET_LOGOUT_TIMEOUT = '[Auth] Set logout timeout';

// --- Interface --- //

export interface Logout {
  type: typeof AUTH_LOGOUT;
}

export interface Login {
  type: typeof AUTH_LOGIN;
  payload: { user: IUser };
}

export interface SetLogoutTimeout {
  type: typeof AUTH_SET_LOGOUT_TIMEOUT;
  payload: { timeout: NodeJS.Timeout | null };
}

// --- Action creators --- //

export const logout = (): Logout => {
  return {
    type: AUTH_LOGOUT,
  };
};

export const login = (user: IUser): Login => {
  return {
    type: AUTH_LOGIN,
    payload: { user },
  };
};

export const setLogoutTimeout = (timeout: NodeJS.Timeout | null): SetLogoutTimeout => {
  return {
    type: AUTH_SET_LOGOUT_TIMEOUT,
    payload: { timeout },
  };
};

export type AuthTypes = Logout | Login | SetLogoutTimeout;

我相信IUser 代码与这个问题无关,所以我省略了它。

问题是,一旦我登录,loginSaga 函数内的行(在 sagas 文件中), const newTimeout: NodeJS.Timeout = yield setTimeout(() =&gt; put(authActions.logout()), logoutTimeout); 这可行,但put(authActions.logout()) 没有任何反应。就像我写的一样。

我也使用redux devtools,5 秒后没有发出任何动作。为什么?

【问题讨论】:

    标签: reactjs typescript redux redux-saga


    【解决方案1】:

    我对您这里的环境感到困惑,或者您可能感到困惑?您正在使用 DOM/窗口函数,但您将 TypeScript 类型声明为 NodeJS.Timeout。该类型 is an object 但在浏览器中调用 setTimeout 返回 a number

    您似乎将超时存储在localStorage 和您的状态中。我不认为其中任何一个都是必要的,因为 saga 有一个内置的 delay 效果来处理这个任务。

    这就是你所需要的:

    import { ForkEffect, put, takeEvery, delay } from "redux-saga/effects";
    import * as authActions from "./actions";
    
    function* loginSaga() {
      yield delay(5000);
      yield put(authActions.logout());
    }
    
    export function* watchAuth(): IterableIterator<ForkEffect> {
      yield takeEvery(authActions.AUTH_LOGIN, loginSaga);
    }
    

    CodeSandbox Link

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 1970-01-01
      相关资源
      最近更新 更多