Search code examples
javascriptreactjsmongodbmeteor

Meteor, useTracker mongo.collection.findOne returns undefined, then correct value


I am getting multiple return values for a Mongo.collection.findOne query by ID, in Meteor JS and React. I think it has to do with the fact that it is rerendering, I have tried to use useEffect but it does not work the way I implemented it, which is just wrapping the lead variable in the useEffect.

Here is my code

import React, { useState, useEffect } from "react";
import Dasboard from "./Dashboard";
import { Container } from "../styles/Main";
import { LeadsCollection } from "../../api/LeadsCollection";
import { Lead } from "../leads/Lead";
import { useTracker } from "meteor/react-meteor-data";

const Walkin = ({ params }) => {
  const [email, setEmail] = useState("");
  const [testIdA, setTestId] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
  };

  const lead = useTracker(() => LeadsCollection.findOne({ _id: params._id }));

  console.log(lead);

  console.log(params._id);

  const deleteLead = ({ _id }) => LeadsCollection.remove(_id);

  return (
    <Container>
      <Dasboard />
      <main className="split">
        <div>
          <h1>Add a lead below</h1>
          <form className="lead-form" onSubmit={handleSubmit}>
            {/* <input
              type="text"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="Type to add new lead"
            /> */}

            <button type="submit">Edit Lead</button>
          </form>
        </div>
        <p>{params._id}</p>
        {/* <Lead key={params._id} lead={lead} onDeleteClick={deleteLead} /> */}
      </main>
    </Container>
  );
};

export default Walkin;

There are three rerenders and this is the result

undefined
Walkin.jsx:20 sLg7dk3KdS7boZuHB
Walkin.jsx:18 undefined
Walkin.jsx:20 sLg7dk3KdS7boZuHB
Walkin.jsx:18 {_id: "sLg7dk3KdS7boZuHB", email: "fasfdas", createdAt: Wed Nov 11 2020 21:40:39 GMT-0700 (Mountain Standard Time)}
Walkin.jsx:20 sLg7dk3KdS7boZuHB

Thanks ahead of time


Solution

  • As JanK. already pointed out, you will want to do the subscription manually. When you do that you will get a .ready function you can use to tell whether the data is available yet on the client, and show a loading page until then.

    Here is an example of how that typically looks in practice:

    const Walkin = ({ params }) => {
    
      const {lead, ready} = useTracker(() => {
        const subscription = Meteor.subscribe('leads', params._id);
        return {
          lead: LeadsCollection.findOne({ _id: params._id })),
          ready: subscription.ready()
        };
      }, [params._id]);
    
      if (!ready) {
        return <div>loading</div>
      }
    
      return <div>
        The actual page where lead is used.
      </div>;
    }