meteor / react-packages

Meteor packages for a great React developer experience
http://guide.meteor.com/react.html
Other
571 stars 157 forks source link

useFind in suspense not working #388

Closed HekTheLastSavior closed 1 year ago

HekTheLastSavior commented 1 year ago

useFind in suspense directory is not being called correctly from the client side in development. what I did was import useFindSuspense which worked as expected .

I think the issue is with assigning the right function to useFind

Grubba27 commented 1 year ago

Do you have a reproduction for your case? useFind with suspense is ideally to be used in the server, as you can see from here If you are only in the client, it is recommended to use useFind as it is sync and you do not need to deal with the suspense api. useSubscribe with suspense can be used anywhere.

Maybe the docs are not that clear about the uses of the suspense version of useFind. Will check them later and try to make them clearer

HekTheLastSavior commented 1 year ago

Ah I see, well I used the default meteor typescript template to test the suspense functionality . useSubscribe and useTracker worked as expected but useFind failed to work.

import React from 'react';
import { Route, Routes } from 'react-router-dom';
import { LinksCollection } from '../../../api/links';
import type { ILink } from '../../../api/links';
import { useSubscribe, useFind } from 'meteor/react-meteor-data/suspense';

function Comp(props: { word: string }) {
  useSubscribe('links');
  const tasksByUser = useFind(LinksCollection, [
    {},
    { sort: { createdAt: -1 } },
  ]);
  const { word } = props;

  // const tasksByUser = useTracker(
  //   'tasksByUser',
  //   () => LinksCollection.find({}, { sort: { createdAt: -1 } }).fetchAsync(), // async call
  // );

  console.log(tasksByUser);
  const makeLink = (link: ILink) => (
    <li key={link._id}>
      <a href={link.url} target="_blank" rel="noreferrer">
        {link.title}
      </a>
    </li>
  );
  return (
    <div className="container">
      These
      <span className="text-white bg-red-600">{word}</span>
      are the Terms and Conditions
      <ul>{tasksByUser.map(makeLink)}</ul>
    </div>
  );
}

error

tracker.js:604 Uncaught TypeError: f is not a function
    at Tracker.withComputation (tracker.js:604:12)
    at Tracker.nonreactive (tracker.js:594:18)
    at useFind.ts:78:28
    at mountMemo (modules.js?hash=8b04ea38967118f9b5fb6d4df48bda2c8a21ec4b:95609:19)
    at Object.useMemo (modules.js?hash=8b04ea38967118f9b5fb6d4df48bda2c8a21ec4b:96054:16)
    at useMemo (modules.js?hash=8b04ea38967118f9b5fb6d4df48bda2c8a21ec4b:74642:21)
    at useFindClient (useFind.ts:75:18)
    at Comp (index.tsx:14:23)
    at renderWithHooks (modules.js?hash=8b04ea38967118f9b5fb6d4df48bda2c8a21ec4b:94689:18)
    at mountIndeterminateComponent (modules.js?hash=8b04ea38967118f9b5fb6d4df48bda2c8a21ec4b:98458:13)
HekTheLastSavior commented 1 year ago

hi @Grubba27 , any update on this issue ?

Grubba27 commented 1 year ago

As I commented, useFind from suspense in the client should not work this way. The default manner that Meteor creates a React app is using a SPA, which means is always a client on React. The way would work in the client if you just started the project would be similar to what you have done:

import React from 'react';
import { Route, Routes } from 'react-router-dom';
import { LinksCollection } from '../../../api/links';
import type { ILink } from '../../../api/links';
import { useSubscribe } from 'meteor/react-meteor-data/suspense';
import {  useFind } from 'meteor/react-meteor-data';
function Comp(props: { word: string }) {
  useSubscribe('links');
  const tasksByUser = useFind(() => LinksCollection.find( {}, { sort: { createdAt: -1 } }));
  const { word } = props;

  // const tasksByUser = useTracker(
  //   'tasksByUser',
  //   () => LinksCollection.find({}, { sort: { createdAt: -1 } }).fetchAsync(), // async call
  // );

  console.log(tasksByUser);
  const makeLink = (link: ILink) => (
    <li key={link._id}>
      <a href={link.url} target="_blank" rel="noreferrer">
        {link.title}
      </a>
    </li>
  );
  return (
    <div className="container">
      These
      <span className="text-white bg-red-600">{word}</span>
      are the Terms and Conditions
      <ul>{tasksByUser.map(makeLink)}</ul>
    </div>
  );
}

We could make an isomorphic wrapper around this suspense version, but I'm not sure. What do you think @radekmie ? Something like this: change this line for this:

export const useFind = Meteor.isClient
  ? (coll, findArgs, deps) => useFindClient(coll.find(...findArgs), deps)
  : useFindSuspense
radekmie commented 1 year ago

Well, yes, it should look like that from the beginning (of course, you'd need to wrap this find in a function). What worries me is the fact that the types didn't suggest it's incorrect - useFind from /suspense should have a union type and not be callable like in these examples.