And sometimes you need to write a fully custom saga may be aggregating data from different end points (http, graphql or local state or anything) In this case, you can do something similar as shown below

import { take, call, put, all, fork, race, select } from 'redux-saga/effects';
import { createStar } from 'redux-nakshatra';
import axios from 'axios';

export const { rootSaga, types, actions, rootReducer } = createStar({
  name: 'users',
  http: {
    url: 'http://localhost:5000/users',
    generateDefault: true
  },
  custom: {
    getUsersAndFriends: {
      saga: function* watchGetUsersAndFriendsRequestSaga(dispatch) {
        while (true) {
          const request = yield take(types.getUsersAndFriends_REQUEST);
          try {
            yield put({
              type: types.getUsers_REQUEST
            });

            yield race([types.getUsers_SUCCESS, types.getUsers_FAILURE]);
            const getUsers = yield select(state => state.getUsers);
            const userIds = getUsers.data.map(o => o.id);
            const getFriendsForUsers = yield call(() =>
              axios({
                url: 'http://localhost:5000/friends',
                data: {
                  userIds
                }
              })
            );
            const result = getUsers.data.map((user, index) => {
              return {
                ...user,
                friend: getFriendsForUsers.data[index]
              };
            });
            yield put({
              type: types.getUsersAndFriends_SUCCESS,
              response: result
            });
          } catch (error) {
            yield put({
              type: types.getUsersAndFriends_FAILURE,
              response: error
            });
          }
        }
      }
    }
  }
});

If you need more low level control, you can add more actions, types, initialState, reducer, sagas separately as well. Example

import { createStar } from 'redux-nakshatra';
import { take, put, race, select } from 'redux-saga/effects';
import { MediaPlayerStatus } from '../constants/mediaPlayerStatus';
import { Howl } from 'howler';

const MediaPlayerActionTypes = {
  playPause_REQUEST: 'playPause_REQUEST',
  playPause_SUCCESS: 'playPause_SUCCESS',
  playPause_FAILURE: 'playPause_FAILURE',
  updateCurrentTrack_REQUEST: 'updateCurrentTrack_REQUEST',
  updateCurrentTrack_SUCCESS: 'updateCurrentTrack_SUCCESS',
  updateCurrentTrack_FAILURE: 'updateCurrentTrack_FAILURE',
  updateStatus: 'updateStatus'
};

const initialState = {
  status: MediaPlayerStatus.PAUSED,
  currentTrack: null,
  updateCurrentTrackFailureMessage: null,
  updateCurrentTrackInProgress: true,
  isLoopingCurrentTrack: false,
  tracks: [
    {
      id: 1,
      title: 'Rave Digger',
      file: 'rave_digger',
      howl: null
    },
    {
      id: 2,
      title: '80s Vibe',
      file: '80s_vibe',
      howl: null
    },
    {
      id: 3,
      title: 'Running Out',
      file: 'running_out',
      howl: null
    }
  ]
};

export const { rootSaga, types, actions, rootReducer } = createStar({
  name: 'mediaPlayer',
  types: MediaPlayerActionTypes,
  actions: {
    updateCurrentTrack(track) {
      return {
        type: MediaPlayerActionTypes.updateCurrentTrack_REQUEST,
        track
      };
    },
    playPause(track) {
      return {
        type: MediaPlayerActionTypes.playPause_REQUEST,
        track
      };
    },
    updateMediaPlayerStatus(status) {
      return {
        type: MediaPlayerActionTypes.updateStatus,
        status
      };
    }
  },
  initialState,
  reducer(state = initialState, action) {
    switch (action.type) {
      case MediaPlayerActionTypes.updateStatus: {
        return {
          ...state,
          status: action.status
        };
      }
      case MediaPlayerActionTypes.updateCurrentTrack_REQUEST: {
        return {
          ...state,
          updateCurrentTrackFailureMessage: null,
          updateCurrentTrackInProgress: true
        };
      }
      case MediaPlayerActionTypes.updateCurrentTrack_SUCCESS: {
        return {
          ...state,
          currentTrack: action.track,
          updateCurrentTrackInProgress: false
        };
      }
      case MediaPlayerActionTypes.updateCurrentTrack_FAILURE: {
        return {
          ...state,
          updateCurrentTrackFailureMessage: action.response,
          updateCurrentTrackInProgress: false
        };
      }
      default:
        return state;
    }
  },
  sagas: {
    *watchUpdateCurrentTrackRequest(dispatch) {
      while (true) {
        const request = yield take(MediaPlayerActionTypes.updateCurrentTrack_REQUEST);

        const track = {
          ...request.track,
          howl: new Howl({
            src: ['./audio/' + request.track.file + '.webm', './audio/' + request.track.file + '.mp3'],
            volume: 1,
            html5: true,
            onplay: function() {
              dispatch({
                type: types.updateStatus,
                status: MediaPlayerStatus.PLAYING
              });
            },
            onload: function() {
              dispatch({
                type: types.updateStatus,
                status: MediaPlayerStatus.LOADED
              });
            },
            onend: function() {
              dispatch({
                type: types.updateStatus,
                status: MediaPlayerStatus.ENDED
              });
            },
            onpause: function() {
              dispatch({
                type: types.updateStatus,
                status: MediaPlayerStatus.PAUSED
              });
            },
            onstop: function() {
              dispatch({
                type: types.updateStatus,
                status: MediaPlayerStatus.STOPPED
              });
            }
          })
        };
        try {
          yield put({
            type: MediaPlayerActionTypes.updateCurrentTrack_SUCCESS,
            track
          });
        } catch (error) {
          console.log(error);
          yield put({
            type: MediaPlayerActionTypes.updateCurrentTrack_FAILURE,
            response: error
          });
        }
      }
    },
    *watchPlayPauseRequestSaga() {
      while (true) {
        const request = yield take(MediaPlayerActionTypes.playPause_REQUEST);
        try {
          const currentTrack = yield select(state => state.mediaPlayer.currentTrack);
          if (currentTrack === null || (currentTrack && currentTrack.id !== request.track.id)) {
            if (currentTrack) {
              currentTrack.howl.pause();
            }

            yield put({
              type: MediaPlayerActionTypes.updateCurrentTrack_REQUEST,
              track: request.track
            });
            yield race([take(MediaPlayerActionTypes.updateCurrentTrack_SUCCESS), take(MediaPlayerActionTypes.updateCurrentTrack_FAILURE)]);

            const updateCurrentTrackFailureMessage = yield select(state => state.mediaPlayer.updateCurrentTrackFailureMessage);
            if (updateCurrentTrackFailureMessage) {
              throw updateCurrentTrackFailureMessage;
            } else {
              const updatedCurrentTrack = yield select(state => state.mediaPlayer.currentTrack);
              updatedCurrentTrack.howl.play();
            }
          }

          if (currentTrack && currentTrack.id === request.track.id) {
            const status = yield select(state => state.mediaPlayer.status);
            if (status === MediaPlayerStatus.PLAYING) {
              currentTrack.howl.pause();
            } else {
              currentTrack.howl.play();
            }
          }

          yield put({
            type: MediaPlayerActionTypes.playPause_SUCCESS
          });
        } catch (error) {
          yield put({
            type: MediaPlayerActionTypes.playPause_FAILURE,
            response: error
          });
        }
      }
    }
  }
});

results matching ""

    No results matching ""