0

Would the below code the correct way to "catch" errors in redux-saga using call or fork? That is when I have the "createItem" function is this correct to NOT catch any errors here and assume this will pass back any exceptions to the generator function "createItemSaga" to catch?

A 2nd question here is I'm noting that I am getting a firestore error passed back (I'm using react-native-firebase) however I am NOT catching it with this code. Refer to console output below. I create a security rule to reject the attempt to create an item in firestore backend to test this.

function createItem(item) {
  firebase.firestore().collection('todos').add(item);
}

export function* createItemSaga() {
  while (true) {
    const action = yield take(ActionTypes.AddListItem_UIRequest);
    console.log('createItemSaga: received AddListItem_UIRequest');
    const { item } = action;    
    yield put({ type: ActionTypes.AddListItemRequested });

    try {
      console.log('createItemSaga: createItem Start');
      yield fork(createItem, item);
      console.log('createItemSaga: createItem Ended');  // <-- This is reached! But why.
    } catch (e) {
      console.log('createItemSaga: error caught. Error=');  <-- Why isn't this point reached
      console.log(pf(e));
      yield put({ type: ActionTypes.AddListItemRejected });
    }
  }
}

The console output is:

createItemSaga: recived AddListItem_UIRequest
createItemSaga: createItem Start
createItemSaga: createItem Ended

Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
    at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
    at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
    at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
    at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
    at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
    at emitTwo (events.js:125:13)
    at process.emit (events.js:213:7)

Note: Did raise potential issue here is case it is related to this libary: https://github.com/invertase/react-native-firebase/issues/727

ADDITIONAL NOTES:

  • I get the same result if I use "call" instead of "fork" in the line "yield fork(createItem, item);"
  • I also get the same results if I incorporate the update attempt in the generate like the following:

Code:

export function* createItemSaga() {
  while (true) {
    const action = yield take(ActionTypes.AddListItem_UIRequest);
    const { item } = action;
    yield put({ type: ActionTypes.AddListItemRequested });
    try {
      console.log('createItemSaga: createItem Start');
      firebase.firestore().collection('todos').add(item);
      console.log('createItemSaga: createItem Ended');
    } catch (e) {
      console.log('createItemSaga: error caught. Error='); 
      console.log(pf(e));
      yield put({ type: ActionTypes.AddListItemRejected });
    }
  }
}

ADDITIONAL NOTES 2:

  • Get same results when I turn the "createItem" function into a generator:

Code:

export function* createItem(item) {
  try {
    console.log('createItem: Start');
    firebase.firestore().collection('todos').add(item);
    console.log('createItem: End');
  } catch (e) {
    console.log('createItem: error');
    console.log(pf(e));
  }
}

    export function* createItemSaga() {
      while (true) {
        const action = yield take(ActionTypes.AddListItem_UIRequest);
        const { item } = action;
        yield put({ type: ActionTypes.AddListItemRequested });

        try {
          console.log('createItemSaga: createItem Start');
          yield call(createItem, item);
          console.log('createItemSaga: createItem Ended');
        } catch (e) {
          console.log('createItemSaga: error caught. Error='); 
          console.log(pf(e));
          yield put({ type: ActionTypes.AddListItemRejected });
        }
      }
    }

Console:

createItemSaga: createItem Start
createItem: Start
createItem: End
createItemSaga: createItem Ended
Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
    at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
    at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
    at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
    at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
    at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
    at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
    at emitTwo (events.js:125:13)
    at process.emit (events.js:213:7)
Greg
  • 34,042
  • 79
  • 253
  • 454

2 Answers2

0

First I think createItem should be a generator (or in other words a saga). And then you don't need a fork but call. That is because fork is not blocking while call is. That's why you are getting the console log. I guess if createItem is a generator your try-catch block will work.

Krasimir
  • 13,306
  • 3
  • 40
  • 55
  • I get the same result if I use "call" instead of "fork" in the line "yield fork(createItem, item);" – Greg Jan 06 '18 at 22:50
  • also same result if I incorporate the update line into the generator - have put this code at the end of the question to show – Greg Jan 06 '18 at 22:54
  • not this if this now points to an error in the underlying react-native-firebase library I'm using for firebase? i.e. does this confirm it is this library not correctly capturing the error, or should my redux-saga code we are looking at it catch this exception in any case? – Greg Jan 06 '18 at 22:56
  • But did you make `createItem` a generator? Like `function* createItem`. – Krasimir Jan 07 '18 at 03:58
  • Yes I get the same result as a generator. I put the code up at the end of the question (if this is what you meant?) – Greg Jan 07 '18 at 07:59
  • Yep, that's what I meant. Is `firebase.firestore().collection('todos').add(item)` throwing an error in this case. I mean if you wrap it in a try-catch block are you able to catch the error. – Krasimir Jan 07 '18 at 08:10
0

Did not get it working using createItem as a separate function, however am now catching the error by contracting all into the one generator per the below:

export function* createItemSaga() {
  while (true) {
    const action = yield take(ActionTypes.AddListItem_UIRequest);
    const { item } = action;
    yield put({ type: ActionTypes.AddListItemRequested });
    try {
      const ref = firebase.firestore().collection('todos');
      yield call([ref, ref.add], item);
      yield put({ type: ActionTypes.AddListItemFulfilled });
    } catch (e) {
      console.log('createItemSaga: error caught. Error='); 
      console.log(pf(e));
      yield put({ type: ActionTypes.AddListItemRejected });
    }
  }
}
Greg
  • 34,042
  • 79
  • 253
  • 454