usePresence throws unhandled error
Currently I have a function inside a hook like the following:
const {presenceData, updateStatus} = usePresence<PresenceDataType>(
channelName,
{/* data */},
);
const startTyping = useCallback(() => {
try {
updateStatus({/* data */});
} catch (e: any) {
// Not caught here?
}
}, [updateStatus]);
and I am seeing the following unhandled error in production:
Error Unable to update presence channel while in suspended state
(native) call
node_modules/ably/build/ably-reactnative.js:1187:32 PartialErrorInfo
node_modules/ably/build/ably-reactnative.js:12482:59 _enterOrUpdateClient
node_modules/ably/build/ably-reactnative.js:2924:21 encode
node_modules/ably/build/ably-reactnative.js:12462:41 _enterOrUpdateClient
(native) apply
node_modules/ably/build/ably-reactnative.js:877:25 anonymous
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:61:9 tryCallTwo
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:216:25 doResolve
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:82:14 Promise
node_modules/ably/build/ably-reactnative.js:876:23 promisify
node_modules/ably/build/ably-reactnative.js:12443:43 _enterOrUpdateClient
node_modules/ably/build/ably-reactnative.js:12426:41 update
node_modules/ably/react/cjs/hooks/usePresence.js:70:36 usePresence
src/hooks/room/use-room-presence.ts:20:19 anonymous
src/components/room/Base/index.tsx:318:22 ?anon_0_
(native) next
node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24 asyncGeneratorStep
node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:27 _next
node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:12 anonymous
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:61:9 tryCallTwo
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:216:25 doResolve
/Users/distiller/react-native/packages/react-native/sdks/hermes/build_iphoneos/lib/InternalBytecode/InternalBytecode.js:82:14 Promise
node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:23 anonymous
src/components/room/InputBar/index.tsx:132:17 anonymous
src/components/room/InputBar/index.tsx:198:20 anonymous
node_modules/react-native/Libraries/Components/TextInput/TextInput.js:1281:45 _onChange
(native) apply
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:22:15 invokeGuardedCallbackImpl
(native) apply
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:40:34 invokeGuardedCallback
(native) apply
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:53:30 invokeGuardedCallbackAndCatchFirstError
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:73:42 executeDispatch
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1125:24 executeDispatchesAndReleaseTopLevel
(native) call
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:361:63 forEachAccumulated
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1161:8 anonymous
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:8457:14 batchedUpdatesImpl
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1106:30 batchedUpdates
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1137:17 _receiveRootNodeIDEvent
node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1178:28 receiveEvent
(native) apply
node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:433:34 __callFunction
node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:113:26 anonymous
node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:368:11 __guard
node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:112:17 callFunctionReturnFlushedQueue
As a side note: I've seen this library throwing other types of exceptions (e.g. in useAbly) when there is no client. Throwing exceptions inside a hook is not normal practice in React (it causes a white screen of death). Same for throwing any sort of exception when it cannot be handled by the caller.
In this case, updateStatus should ideally be a Promise and resolve/reject.
Hey @danielrhodes,
Thanks for reporting this! updateStatus is actually an asynchronous function, but we don't return a Promise right now. We will fix this. In the meantime, I recommend looking at connectionError and channelError before calling updateStatus to prevent this error. Alternatively, you can use a direct API call:
const { presenceData, updateStatus } = usePresence<PresenceDataType>(
channelName,
{/* data */},
);
const { channel } = useChannel(channelName);
const startTyping = useCallback(async () => {
try {
await channel.presence.update({/* data */});
} catch (e: any) {
// catch here
}
}, [channel.presence]);
updateStatus returned by the usePresence hook has been updated to return Promise and be async. This change will be included in the next minor release for ably-js