Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to pass redux saga payload to another action

I have a functioning redux saga, but I can't stop thinking about how ugly it looks. What I'm trying to do is admittedly a little contrived to simulate async without needing it, but I want to delay one second and then call another function - similar to the tutorial. The difference from the tutorial (which is a simple incrementer) is that I actually need to pass along information. Here is how I'm doing it:

import { delay } from 'redux-saga';
import { put, call, takeEvery, all } from 'redux-saga/effects';

// Our worker Saga: will perform the add employee task
export function* addEmployeeAsync(action) {
  yield call(delay, 1000);
  console.log(action); // logs undefined on initial app load
  const payload = action && action.payload;
  yield put({ type: 'ADD_EMPLOYEE', payload });
}

// Our watcher Saga: spawn a new addEmployeeAsync task on each ADD_EMPLOYEE_ASYNC
export function* watchAddEmployeeAsync() {
  yield takeEvery('ADD_EMPLOYEE_ASYNC', addEmployeeAsync);
}    

export default function* rootSaga() {
  yield all([
    addEmployeeAsync(),
    watchAddEmployeeAsync(),
  ]);
}

The function is also being called on page load with a payload of undefined, which may indicate a larger problem I am missing.

The complete code base is here: https://github.com/LukeSchlangen/react-salary-calculator/tree/9ce96409080a3a3f702465791cd28c4c83cadc6f

To reiterate, this code is working, but I can't help but think that there must be a cleaner way to do this.

like image 322
Luke Schlangen Avatar asked Feb 04 '18 16:02

Luke Schlangen


People also ask

How do I dispatch actions from Saga?

Create a plain JavaScript Object to instruct the middleware that we need to dispatch some action, and let the middleware perform the real dispatch. This way we can test the Generator's dispatch in the same way: by inspecting the yielded Effect and making sure it contains the correct instructions.

What is takeEvery and takeLatest in redux saga?

takeEvery - enables the use of several fetchData objects at the same time. At a given moment, we can start a new fetchData task while there are still one or more previous fetchData tasks which have not yet terminated. takeLatest - Only one fetchData task can be active at any given moment.

How do I call saga from another saga?

Calling a saga from another saga is as simply as doing a call effect.

Is redux saga deprecated?

Such a powerful & elegant tool as Redux-Saga, a Redux side effect manager, is said to be deprecated, and no longer being maintained, starting from Jan 27, 2021.


1 Answers

I think I found it. I don't think I need to export the worker saga in the all at the bottom of the file. I think just exporting the watcher saga takes care of it (and prevents the initial call where the payload is undefined).

Here is what I ended up with:

import { delay } from 'redux-saga';
import { put, call, takeEvery, all } from 'redux-saga/effects';

// Our worker Saga: will perform the add employee task
export function* addEmployeeAsync({ payload }) {
  yield call(delay, 1000);
  yield put({ type: 'ADD_EMPLOYEE', payload });
}

// Our watcher Saga: spawn a new addEmployeeAsync task on each ADD_EMPLOYEE_ASYNC
export function* watchAddEmployeeAsync() {
  yield takeEvery('ADD_EMPLOYEE_ASYNC', addEmployeeAsync);
}

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

This seems much cleaner to me (since I don't have to do the check to see if it is undefined).

like image 156
Luke Schlangen Avatar answered Sep 18 '22 14:09

Luke Schlangen