Home reactjs Logic in redux-saga

Logic in redux-saga

Author

Date

Category

Expected behavior: requests are made to the api with an interval of 1.5 seconds until a successful request is completed, or the sendMessageCancel action is called with the required id.
What’s available: after invoking the action, the state changes, but requests continue to go with an interval of 1.5 seconds
P.S. logs after race execution are also not called

Sagas:

import {takeEvery, delay, call, put, race, take} from 'redux-saga / effects';
import axios, {AxiosResponse} from 'axios';
import {sendMessageStart, sendMessageSuccess, sendMessageProgress, sendMessageCancel, ISendMessage} from './slice';
import sendMessageAPI from '../../utils/api/sendMessageAPI';
import {ISendMessageResponse} from '../../interfaces/Responses/chat/ISendMessageResponse';
function * sendMessageSaga ({payload}: ReturnType & lt; typeof sendMessageStart & gt;) {
  const {token, cancel} = axios.CancelToken.source ();
  while (true) {
    try {
      let {action, api} = yield race ({
        action: take (action = & gt; {
          return action.type == sendMessageCancel.type & amp; & amp; action.payload == payload._id
        }),
        api: call (sendMessageAPI.send, payload, token, function * (progress: number) {
          yield put (sendMessageProgress ({message: payload._id, progress}));
        })
      });
      const resp = api as AxiosResponse & lt; ISendMessageResponse & gt ;;
      console.log (resp);
      console.log (action);
      if (resp)
        yield put (sendMessageSuccess (payload._id));
      else {
        console.log ('Cancel');
        return cancel ();
      }
      break;
    } catch (e) {
      console.log (e);
      yield delay (1500);
    }
  }
}
export default function * sendMessageWatchSaga () {
  yield takeEvery (sendMessageStart.type, sendMessageSaga);
}

API

import axios, {CancelToken, CancelTokenSource} from 'axios';
import {ISendMessage} from '../../redux/sendMessage/slice';
import {ISendMessageResponse} from '../../interfaces/Responses/chat/ISendMessageResponse';
const client = axios.create ({
  baseURL: process.env.API_URL || 'http: // localhost: 5000'
});
const sendMessageAPI = {
  async send (message: ISendMessage, cancelToken: CancelToken, callback: (progress: number) = & gt; void) {
    return client.post & lt; ISendMessageResponse & gt; ('/ messages', message, {
      headers: {Authorization: `Bearer $ {localStorage.getItem ('token')}`},
      cancelToken: cancelToken,
      onUploadProgress: progressEvent = & gt; {
        callback (progressEvent.loaded / progressEvent.total);
      }
    });
  }
};
export default sendMessageAPI;

Slice

import {createSlice, PayloadAction} from '@ reduxjs / toolkit';
import {RootState} from '../index';
import {IMessage} from '../../interfaces/IMessage';
// create initial state
export type ISendMessage = {file ?: File} & amp; IMessage
type ISendMessageItem = {
  progress: number,
  msg: ISendMessage
};
type ISendMessageState = Record & lt; string, ISendMessageItem & gt ;;
const initialState: ISendMessageState = {};
// create slice
const sendMessageSlice = createSlice ({
  name: 'sendMessage',
  initialState,
  reducers: {
    start (state, action: PayloadAction & lt; ISendMessage & gt;) {
      state [action.payload._id] = {
        progress: 0,
        msg: action.payload
      };
    },
    success (state, action: PayloadAction & lt; string & gt;) {
      delete state [action.payload];
    },
    progress (state, action: PayloadAction & lt; {message: string, progress: number} & gt;) {
      state [action.payload.message] .progress = action.payload.progress;
    },
    cancel (state, action: PayloadAction & lt; string & gt;) {
      delete state [action.payload];
    }
  }
});
// selectors 
Export Const SelectsendMessageState = (State: RootState) = & gt; state.sendMessage;
Export Const SelectsendMessage = (ID: String) = & gt; (State: rootstate) = & gt; SelectsendMessageState (State) [ID];
Export Const SelectSendMessagesFordialog = (ID: String) = & gt;
  (State: rootstate) = & gt; Object.Values ​​(State). Filter (IT = & gt; it.msg.dialog._id == id);
// Exports.
EXPORT CONST {
  Start: SendMessagestart, Success: SendMessageSuccess,
  Progress: SendMessageProgress, Cancel: SendMessageCancel
} = SendMessagesLice.Actions;
Export Default SendMessagesLice.Reducer;

Answer 1

The problem was banal, the call of the API and the subsequent delay occupied the flow of saga, and she simply ignored the Calling of the SendMessageCancel action, so I used fork and everything earned

import {takeevery, delay, call, put, fork, take, Cancel, Cancelled, Race, SELECT} from 'Redux- SAGA / EFFECTS ';
Import Axios, {axiosreSponse, CancelToken} from 'Axios';
Import {iSendMessageresponse} from '../../interfaces/responses/chat/isendMessageresponse';
Import {SendMessageStart, SendMessageSuccess, SendMessageProgress, SendMessageCancel, iSendMessage} from './slice';
Import {MessagesAdd} from '../messages';
Import {dialogsadd} from '../dialogs';
import {chatmessagesadd} from '../chat/messages/slice';
Import SendMessageApi from '../../utils/api/sendMessageApi';
Import {selectchatdialogstate} from '../chat/dialog/slice';
Function * SendMessageApi (Data: ISendMessage, Token: CancelToken) {
  Let i = 0;
  While (True) {
    Try {
      // Make API Call
      Const Resp: AXIOSRESPONSE & LT; ISendMessageResponse & GT; = Yield Call (SendMessageApi.send,
        Data, Token, Function * (PROGRESS: NUMBER) {
          Yield Put (SendMessageProgress ({Message: Data._ID, Progress}));
        });
      // Get Current Dialog
      const {dialog} = Yield Select (SelectChatdialOGstate);
      // Update State
      Yield Put (SendMessageSuccess (Data._ID));
      Yield Put (MessagesAdd ({
        ... resp.data.newmessage,
        Author: resp.data.newmessage.Author._id
      } As Any));
      // Update Dialog Last Message
      Yield PUT (Dialogsadd ({_ ID: Data.dialog._ID, LastMessage: resp.data.newmessage._id} As Any));
      if (dialog == data.dialog._id)
        Yield Put (ChatmessagesAdd ({
          Message: resp.data.newmessage._ID,
          FIRST: True.
        }));
      // Exit Loop.
      Break;
    } Catch (E) {
      // EXIT ON TASK CANCEL
      If (Yield Cancelled ())
        Return;
      // Increase Interval.
      IF (I & LT; 60)
        I ++;
      Yield Delay (1000 * i);
    }
  }
}
Function * SendMessagesAga ({Payload}: ReturntType & lt; Typeof SendMessagestart & gt;) {
  Const Source = axios.cancelToken.source (),
    // Start Send Messages
    Task = Yield Fork (SendMessageApi, Payload, Source.token);
  // Start Race Between Success Sending and Cancellation
  Const {API, CancelMessage} = Yield Race ({
    API: Take (Action = & gt; action.type == SendMessageSuccess.Type & amp; & amp; action.payload == payload._id),
    CancelMessage: Take (Action = & GT; Action.Type == SendMessagecancel.Type & amp; & amp; action.payload == payload._id)
  });
  If (CancelMessage) {
    // Stop API Calls
    Yield Cancel (Task);
    source.cancel ();
  }
}
Export Default Function * SendMessageWatchsaga () {
  Yield TakeEvery (SendMessagestart.Type, SendMessagesAga);
}

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions