Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspense throws undefined error #413

Open
ToastHawaii opened this issue Nov 13, 2024 · 4 comments · May be fixed by #414
Open

Suspense throws undefined error #413

ToastHawaii opened this issue Nov 13, 2024 · 4 comments · May be fixed by #414

Comments

@ToastHawaii
Copy link

We upgrade from a very old projekt (Openki). We started with blaze and iron router and now migrate to react, async await and meteor v3 step by step. (Working Branch)

Currently we found out that we need react-meteor-data/suspense to support some async await calls on loading data.

If a change happend in the UI the render breaks and if ('error' in cachedSubscription) throw cachedSubscription.error is thrown with a undefined.

I gues it happens because we have mixed up a lot of diffrend librarys with diffrent Tracker in it and something is not update nice. We use blaze, react, react in blaze, iron-router (fixed for v3),

@ToastHawaii ToastHawaii linked a pull request Nov 13, 2024 that will close this issue
@allenfuller
Copy link

I've run into the same issue. Suspense useSubscribe works just fine on a half dozen other subscriptions throughout the app. This one just blows up. The only difference is that it has a parameter that is updated from a useState hook.

Here's how the component starts in case it's helpful for troubleshooting @Grubba27 @radekmie

const AppGrid = () => {
  const [selectedCategory, setSelectedCategory] = useState(null);
  const [searchTerm, setSearchTerm] = useState('');

  useSubscribe('apps.list', { limit: 100, category: selectedCategory });
  const findObj = {};

  if (selectedCategory) {
    findObj.category = selectedCategory;
  }

  const apps = useFind(Apps, [findObj, { sort: { name: 1 } }]);

  if (Meteor.isDevelopment) {
    console.log('AppGrid.selectedCategory', selectedCategory);
    console.log('AppGrid.apps', apps);
  }

@allenfuller
Copy link

Update: (Always happens when you post a comment about something).

Discovered the issue happens when I have put a this.stop() on the associated publication.

I use Roles to check for the user's access to the publication before sending data over the wire. If they do not have access, they get a this.stop()

Meteor.publish('apps.list', async function (options) {
  if (Meteor.isDevelopment) {
    console.log('\npublish.apps.list starting');
    console.log(JSON.stringify(options));
  }

  if (!this.userId) {
    console.warn('publish.apps.list - no userId');
    this.ready();
    return [];
  }

  check(options, {
    limit: Match.Maybe(Number),
    category: Match.Maybe(null, String),
  });

  const thisUser = await Meteor.users.findOneAsync(
    { _id: this.userId },
    { fields: { tenant: 1 } },
  );
  const { tenant } = thisUser || {};

  const hasAccess = await Roles.userIsInRoleAsync(this.userId, 'system_read', tenant);

  if (hasAccess) {
    const { limit = 100, category } = options || {};
    const queryObj = {};

    if (category) {
      queryObj.tags = { $in: [category] };
    }

    return Apps.find(queryObj, {
      fields: fieldsToPublish,
      limit,
      sort: { name: 1 },
    });
  }
  this.stop();
  return [];
});

After fixing the Roles check (initially had the wrong role) the page now works.

@StorytellerCZ
Copy link
Collaborator

this.ready() I think is the more common approach to return nothing from the subscription. Will have to look more into it.

@radekmie
Copy link
Collaborator

Yeah, it's a simple overlook here. We assume that all onStops happen because of an error and not because the server wanted to. In that case the subscription is "kind of failed" (the data is not there) but there's no error, so the error is undefined.

I see three ways out:

  1. Document that if useSubscribe throws undefined, it's because of the server stopping the subscription. Definitely not ideal from the DX perspective, but "works".
  2. Add a default "subscription stopped" error in the onStop handler. Same as above but with better DX.
  3. Treat stopped subscriptions as not failed. This would need to be hidden behind a setting (opt-in), as otherwise people may assume that the data is there, even though it's not. Then the returned value of useSubscribe could be a boolean instead of null, telling whether the subscription is ready or not.

@StorytellerCZ StorytellerCZ linked a pull request Mar 19, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants