在 redux-saga 中使用 call 和 put 是正确的方式

发布于 2025-01-16 14:04:25 字数 3407 浏览 0 评论 0原文

我在我的 React 应用程序中使用 redux-saga。然而,我对如何以正确的方式实现看涨期权和看跌期权效果有点困惑。

我想将新数据添加到我的 redux 状态,但是每当我使用下面列出的设置时,新的事务对象就会出现在我的 UI 中,但不会出现在 JSON 服务器中。如果我刷新页面,新添加的项目就会消失。

我的设置看起来与此完全相同的原因之一是我读到,每当分派操作时,操作都应该使用 put 效果来实现,并且这对于测试您的 Redux Saga 很有好处。

在我的情况下使用 put 效果的正确方法是什么?

我进行了以下设置:

Redux Saga

import { put, call, take, takeLatest} from "redux-saga/effects";

import {
  ADD_TRANSACTION,
  addTransaction
} from "state/transactions";
// POST
async function addTransactionData(payload) {
  try {
    const response = await fetch(`http://localhost:3010/transactions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });
    const result = await response.json(payload);
    return result;
  } catch (error) {
    throw error;
  }
}

function* onAddTransactionData({ payload }) {
  try {
    const data = yield call(addTransactionData, payload);
    yield put(addTransaction(data));
  } catch (error) {
    console.log(error);
  }
}

export function* addTransactionWatcherSaga() {
  yield take(ADD_TRANSACTION, onAddTransactionData);
}

Root Saga

import { all, call } from "redux-saga/effects";
import {
  transactionsWatcherSaga,
  removeTransactionWatcherSaga,
  addTransactionWatcherSaga
} from "state/transactions";

export function* rootSaga() {
  yield all([
    call(transactionsWatcherSaga),
    call(removeTransactionWatcherSaga),
    call(addTransactionWatcherSaga)
  ]);
}

Action Creators

// ....
export const addTransaction = ({
  name,
  amount,
  description,
  isExpense
} = {}) => {
  return {
    type: ADD_TRANSACTION,
    payload: {
      id: uuidv4(),
      name,
      amount,
      description,
      isExpense
    }
  };
};
//...

Reducer

/* ==============================================
============== TRANSACTIONS REDUCER ============
=============================================== */
import {
  ADD_TRANSACTION,
  REMOVE_TRANSACTION,
  EDIT_TRANSACTION,
  GET_TRANSACTIONS,
  SET_TRANSACTIONS
} from "state/transactions";

const initialState = {
  transactions: [],
  transactionsLoader: false,
  error: {
    message: ""
  }
};

export const transactionsReducer = (state = initialState, action) => {
  switch (action.type) {
   // ...
    case ADD_TRANSACTION:
      return {
        ...state,
        transactions: [...state.transactions, action.payload]
      };
   // ....
    default:
      return state;
  }
};

我可以成功调度一个的唯一方法POST请求是这样的,但是不包括put效果。

// POST
async function addTransactionData(payload) {
  try {
    const response = await fetch(`http://localhost:3010/transactions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });
    const result = await response.json(payload);
    console.log(result);
    return result;
  } catch (error) {
    throw error;
  }
}

function* onAddTransactionData({ payload }) {
  console.log(payload);

  try {
    yield call(addTransactionData, payload);
  } catch (error) {
    console.log(error);
  }
}

export function* addTransactionWatcherSaga() {
  yield takeLatest(ADD_TRANSACTION, onAddTransactionData);
}

I'm using redux-saga in my React application. However, I'm a bit confused of how call and put effects should be implemented in the right way.

I want to add new data to my redux state, but whenever I use the set up listed bellow, new transactions object appears in my UI, but not in the JSON Server. If I refresh the page, the newly added item disappears.

One of the reasons my set up looks exactly like this is that I read that actions should be implemented with put effect whenever dispatching an action and that it's good for testing your Redux Saga.

What is the right way to use put effect in my situation?

I have the following set up:

Redux Saga

import { put, call, take, takeLatest} from "redux-saga/effects";

import {
  ADD_TRANSACTION,
  addTransaction
} from "state/transactions";
// POST
async function addTransactionData(payload) {
  try {
    const response = await fetch(`http://localhost:3010/transactions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });
    const result = await response.json(payload);
    return result;
  } catch (error) {
    throw error;
  }
}

function* onAddTransactionData({ payload }) {
  try {
    const data = yield call(addTransactionData, payload);
    yield put(addTransaction(data));
  } catch (error) {
    console.log(error);
  }
}

export function* addTransactionWatcherSaga() {
  yield take(ADD_TRANSACTION, onAddTransactionData);
}

Root Saga

import { all, call } from "redux-saga/effects";
import {
  transactionsWatcherSaga,
  removeTransactionWatcherSaga,
  addTransactionWatcherSaga
} from "state/transactions";

export function* rootSaga() {
  yield all([
    call(transactionsWatcherSaga),
    call(removeTransactionWatcherSaga),
    call(addTransactionWatcherSaga)
  ]);
}

Action creators

// ....
export const addTransaction = ({
  name,
  amount,
  description,
  isExpense
} = {}) => {
  return {
    type: ADD_TRANSACTION,
    payload: {
      id: uuidv4(),
      name,
      amount,
      description,
      isExpense
    }
  };
};
//...

Reducer

/* ==============================================
============== TRANSACTIONS REDUCER ============
=============================================== */
import {
  ADD_TRANSACTION,
  REMOVE_TRANSACTION,
  EDIT_TRANSACTION,
  GET_TRANSACTIONS,
  SET_TRANSACTIONS
} from "state/transactions";

const initialState = {
  transactions: [],
  transactionsLoader: false,
  error: {
    message: ""
  }
};

export const transactionsReducer = (state = initialState, action) => {
  switch (action.type) {
   // ...
    case ADD_TRANSACTION:
      return {
        ...state,
        transactions: [...state.transactions, action.payload]
      };
   // ....
    default:
      return state;
  }
};

The only way I can succesfully dispatch a POST request is this, but that does not include put effect.

// POST
async function addTransactionData(payload) {
  try {
    const response = await fetch(`http://localhost:3010/transactions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });
    const result = await response.json(payload);
    console.log(result);
    return result;
  } catch (error) {
    throw error;
  }
}

function* onAddTransactionData({ payload }) {
  console.log(payload);

  try {
    yield call(addTransactionData, payload);
  } catch (error) {
    console.log(error);
  }
}

export function* addTransactionWatcherSaga() {
  yield takeLatest(ADD_TRANSACTION, onAddTransactionData);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

终陌 2025-01-23 14:04:26

您的传奇配置不正确。每次发生 ADD_TRANSACTION 操作时,您都会为 onAddTransactionData 启动一个传奇,但 onAddTransactionData 最终会执行 ADD_TRANSACTION 操作,因此您将循环(除非您从 API 中收到错误)。

通常,您会执行诸如 ADD_TRANSACTION 之类的操作,该操作将启动传奇 onAddTransactionData。该传奇将进行 API 调用并返回结果。然后,saga 会放置一个类似 LOAD_TRANSACTION_RESULTS 的操作,该操作会将 API 调用的结果包含在有效负载中,并且您的减速器将使用该结果更新您的状态。

Your saga is not configured correctly. Every time a ADD_TRANSACTION action happens you are starting a saga for onAddTransactionData but onAddTransactionData ultimately puts the ADD_TRANSACTION action, so you will loop (unless you get an error from the API).

Typically you'd have an action like ADD_TRANSACTION which would start a saga onAddTransactionData. That saga would make the API call and get back the result. Then the saga would put an action like LOAD_TRANSACTION_RESULTS that would have the result of the API call in the payload, and your reducer would update your state with that result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文