关于redux saga的导入方法

About the import method of redux saga

我是一名 2 个月的前端开发人员。

我是在进公司的同时学习React的, 所以有很多地方我不太了解

我目前正在分析代码以进行代码维护, 但是代码中有一个深奥的部分。

首先,在saga中,没有导入action函数的部分。 (即使在根传奇中。)

那么,是否可以在代码中隐式导入?

我附上了一些代码以帮助您理解。

rootSaga.js

import { all } from "redux-saga/effects";

import watcherLogin from "store/sagas/login";
import watcherSignUp from "store/sagas/signup";

export default function* rootSaga() {
  yield all([
    watcherLogin(),
    watcherSignUp(),
  ]);
}

watcherLogin() > index.js

export { default } from "./watcherLoginSaga"

watcherLogin() > watcherLoginSaga.js

import { all, put, fork, takeLatest } from "redux-saga/effects";
import Cookies from "universal-cookie";
import { fetchData } from "store/sagas/baseSaga";

function* onRequestLogin(action) {
  const payload = action.payload;
  const { history } = payload;
  const successAction = (res) => {

    const cookies = new Cookies();
    cookies.set("hdmKey", res.data, {
      path: "/",
      maxAge: 3600,
    });
    return function* () {

      const payload = res;
      yield put({
        type: "login/GET_USERINFO_REQUEST",
        payload: {
          method: "get",
          api: "getUserInfo",
          // token: res.data.key,
          history,
        },
      });
      yield put({
        type: "login/LOGIN_REQUEST_SUCCESS",
        payload,
      });
      yield put({
        type: "base/IS_LOGGED",
        payload,
      });
      yield history.push("/");
    };
  };
  const failureAction = (res) => {

    return function* () {

      yield put({
        type: "base/SHOW_MODAL",
        payload: {
          dark: true,
          modalName: "alert",
          modalContent: "login failure",
          modalStyle: "purpleGradientStyle",
          modalTitle: "Wait!",
        },
      });
    };
  };
  yield fork(fetchData, payload, successAction, failureAction);
}
...

export default function* watcherLoginSaga() {
  yield all([
    takeLatest("login/LOGIN_REQUEST", onRequestLogin),
  ]);
}

登录模块 > index.js

export { default } from "./loginModule";

登录模块 > loginModule.js

import createReducer from "store/createReducer";
import { changeStateDeep } from "lib/commonFunction";

export const types = {
  LOGIN_REQUEST: "login/LOGIN_REQUEST",
  LOGIN_REQUEST_SUCCESS: "login/LOGIN_REQUEST_SUCCESS",
  ...
};
export const actions = {
  loginRequest: (payload) => ({
    type: types.LOGIN_REQUEST,
    payload,
  }),
...
};
const INITIAL_STATE = {
  data: {
    isLogged: false,
    ...
  },
};
const reducer = createReducer(INITIAL_STATE, {

  [types.ON_LOGIN]: (state, action) => {
    state.data.isLogged = true;
  },
  [types.LOGIN_REQUEST_SUCCESS]: (state, action) => {
    state.data.isLogged = true;
    state.data.key = action.payload?.key || "key";
  },
...
});
export default reducer;

如果您能提供一点帮助,我将不胜感激。

action 只是一个带有 属性 type 的普通 javascript 对象。作为约定(但不是严格要求),操作对象将其数据存储在可选的 属性 payload.

actionCreator 是一个接受 0 到多个参数并使用它们创建动作对象的函数。

您在发布的代码中看到的内容有效,但并不理想。我猜测对 loginModule.js 文件进行了某些改进,但这些改进并未带到 watcherLoginSaga.js 文件中。

您的 types 对象允许您使用变量 types.LOGIN_REQUEST 而不是原始字符串 "login/LOGIN_REQUEST"。这有很多好处:

  • 您的 IDE 获得了自动完成等智能感知支持
  • 不用担心打错字
  • 你可以改变底层raw的值string,你只需要改变一个地方

最后一个很关键,因为如果您现在将 types.LOGIN_REQUEST 的值更改为 "login/LOGIN_REQUEST" 以外的任何值,您的 sagas 将停止工作,因为它们使用的是原始字符串。所以你认为 saga 应该 从动作中导入是绝对正确的。我建议您导入 types 并用相应的变量替换字符串。

传奇通过 put 调度的操作也发生了同样的情况。 这段代码中发生的事情是 saga 从 typepayload 创建一个原始动作对象本身,而不是通过动作创建者函数创建它。 很好,但不是很好。与类型一样,动作创建者是一个抽象级别,可以更好地维护代码。如果 action creator 函数尚不存在,您绝对可以将 saga 中的逻辑提取出来。

例如,您的基本模块可以包括:

const types = {
  IS_LOGGED: "base/IS_LOGGED",
  SHOW_MODAL: "base/SHOW_MODAL"
};

export const actions = {
  isLogged: (payload) => ({
    type: types.IS_LOGGED,
    payload
  }),
  showLoginFailure: () => ({
    type: types.SHOW_MODAL,
    payload: {
      dark: true,
      modalName: "alert",
      modalContent: "login failure",
      modalStyle: "purpleGradientStyle",
      modalTitle: "Wait!"
    }
  })
};

并且您可以将创建操作的逻辑从您的 saga 中移开。

import { all, put, fork, takeLatest } from "redux-saga/effects";
import Cookies from "universal-cookie";
import { fetchData } from "store/sagas/baseSaga";
import {actions as loginActions, types as loginTypes} from "../some_path/loginModule";
import {actions as baseActions} from "../some_path/baseModule";

function* onRequestLogin(action) {
  const payload = action.payload;
  const { history } = payload;
  const successAction = (res) => {

    const cookies = new Cookies();
    cookies.set("hdmKey", res.data, {
      path: "/",
      maxAge: 3600,
    });
    return function* () {

      const payload = res;
      yield put(loginActions.getUserInfoSuccess(history));
      yield put(loginActions.loginSuccess(payload));
      yield put(baseActions.isLogged(payload));
      yield history.push("/");
    };
  };
  const failureAction = (res) => {

    return function* () {

      yield put(baseActions.showLoginFailure());
    };
  };
  yield fork(fetchData, payload, successAction, failureAction);
}

export default function* watcherLoginSaga() {
  yield all([
    takeLatest(loginTypes.LOGIN_REQUEST, onRequestLogin),
  ]);
}