Error handling in subscriptions with React


#1

Hi all,

I’m using Meteor 1.2.1 with React and I’m struggling to figure out how to handle errors from subscriptions gracefully. I have a very simple example here where I want to render the Error component if the subscription fails. The behavior I’m observing is that if an error occurs in the subscription render() is never called. I am also unable to call setState() from getMeteorData() so I am lost as to how I could display a useful message to the user. Any feedback is welcome!!

  getMeteorData: function() {
    let error = null;
    let itemHandle = Meteor.subscribe('ItemsPub', self.props.itemId, {
      onStop: function(args) {
        if (args.error) {
          error = args.error;
        }
      }
    } );
    let item = Items.findOne({"itemId":self.props.itemId});

    return {
      error: error,
      loading: !itemHandle.ready(),
      item: item
    };
  },
  render() {
    if (this.data.error) return ( <Error message={this.data.error}/> );
    if (this.data.loading) return (<LoadingSpinner/>);
    return (
      <div>Item: {this.data.item.title}</div>
    );
  },

#2

It seems that this was posted a long time ago, but I just had to tackle a similar scenario.
This is what I did:

let itemError
const ItemContainer = createContainer(props => {
  const handle = Meteor.subscribe('Items', {
    onStop: (error) => {
      itemError = error
    }
  })
  
  return {
    loadingItem: !itemHandle.ready(),
    itemError,
    items: Items.find({}).fetch()
  }
}, Item)

For the rendering part:

render () {
    const { items, itemError, loadingItem } = this.props
    if (itemError) return <h1>{itemError.error.message}</h1>
    if (loadingItem) return <h1>Loading...</h1>

    return (
      ...
    )
  }

I’m using the low-level publication API to pull data from a 3rd party REST API, so this is what I found to work so the error would be picked up on the client:
(Inside the “publish” callback):

if (!this.userId) {
    this.ready()
    this.error(new Meteor.Error({message: 'Authentication required'}))
    return
}

If the “ready” trigger isn’t used before “error”, the UI doesn’t get updated.