简体   繁体   中英

Why is Collection.find() not working on my Meteor client?

I was sure to correctly create my collection, publish the data, subscribe to the right publication, and check that the data was actually appearing in the Mongo Shell. I even console.log()'d the data that was being published to ensure that the publication was working. Yet, the following line of code fails to return anything:

const maybeMeet = Meets.find({meetId: maybeId}).fetch();

This could be found below and in Line 39 of /client/imports/routes/routes.js in the linked repo.

At one point, I even tried to create a new Meteor method 'meets.query' that would just publish all the data I need, (insecurely) averting the need for a publications and subscriptions (it's now commented out on Line 59 of /client/imports/api/meets.js ). That too did not work. In general, it seems as if the client can't receive any data from the server, but going from the client to the server seems to work (I could insert things into my Meets collection).

Here is the source of the problem (part of routes.js ):

export const routes = (
    <div id='app'>
    <Header />
    <Router history={browserHistory}>
      <Switch>
        <Route exact path="/" render={() => {
          return <Landing />
        }} />
        <Route path="/before" render={() => {
          return <Before />
        }} />
        <Route path="/meet" render={() => {
          Meteor.subscribe('allMeets');

          const maybeId = queryString.parse(location.search).m;

          console.log(typeof maybeId);
          console.log(maybeId);

          const maybeMeet = Meets.find({meetId: maybeId}).fetch(); //***RETURNS NOTHING!***

          return maybeMeet.length ? <Created meet={maybeMeet[0]} /> : <NotFound />;
        }} />
        <Route path="*" render={() => {
          return <NotFound />
        }} />
      </Switch>
    </Router>
  </div>
);

Here is where I publish the data (part of `meets.js'):

if (Meteor.isServer) {
  Meteor.publish('allMeets', function() {
    return Meets.find();
  });
}

Please see the repo for the entirety of the code if you need to see more: https://github.com/kpeluso/meetr

I apologize to for the messy code - it's a new project.

The problem here is that a subscribe operation is asynchronous, as it has to fetch data from the server.

The solution is to wrap the component rendered by the router in a WithTracker so that it will re-run when the data is available and start rendering to the DOM

More information on how to do that is on the docs: https://guide.meteor.com/react.html#using-withTracker

WithTracker, check meteor docs https://guide.meteor.com/react.html#using-withTracker

For example in this code, for the APP component, withTracker keeps reactivity in sync with the subscription, and the things list fetching the collection.

export default withTracker(() => {
  Meteor.subscribe('allThings')
  return {
    things: Things.find({}).fetch()
  }
})(App);

Checkout my meteor react boilerplate.

https://github.com/pkcwong/meteor-react-starter

I use the package meteor/react-meteor-data . The HOF withTracker is the right solution.

In my Created component, I had a Tracker.autorun() with an error in it, and that led to everything else crashing. The call to Meteor.subscribe(allMeets); in my router is also, as mentioned, async and was not being handled as such.

I found the withTracker to be cumbersome, but I gleamed a lot of inspiration from its docs. As a result, the edited code in my Created component now includes this:

componentDidMount() {
    this.meetTracker = Tracker.autorun(() => {
      const subHandle = Meteor.subscribe('allMeets');
      const loading = !subHandle.ready();

      const maybeMeet = Meets.find({meetId: this.props.meetId}).fetch();
      if (!maybeMeet.length && loading) {
        this.setState({active: <Loading />});
      } else if (!loading) {
        if (maybeMeet.length) {
          this.setState({active: <During meet={maybeMeet[0]} />});
        } else {
          createHistory().push('/PageNotFound');
          window.location.reload();
        }
      }
    });
  }

... and the code in my router now includes this:

  <Route path="/meet" render={() => {
    const maybeId = queryString.parse(location.search).m;
    return <Created meetId={maybeId} />
  }} />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM