简体   繁体   中英

Why is the Meteor collection not populating on the first render()?

I am a bit confused as to how to get this to work. I have three components - ReportsWrapper , ReportsNearby , and ReportSingle :

1.) ReportsWrapper gets the device location data then calls ReportsNearby passing the location as a prop

2.) ReportsNearby then uses that location to populate a "reports" collection from the mongodb

3.) Each record from "reports" is rendered via a ReportSingle component

Problem is that the "reports" collection does not populate the page at first load. The page loads, no data (data from mongodb) is shown on the client.

If I navigate to a different page (like /about or /settings) then back to ReportsWrapper, the collection seems to populate as expected and a ReportSingle is displayed for each record. Once I refresh on ReportsWrapper the collection is once again empty.

Any ideas?

ReportsWrapper.jsx

import React, {Component} from "react";
import TrackerReact from "meteor/ultimatejs:tracker-react";    
import ReportsNearby from "./ReportsNearby.jsx";

export default class ReportsWrapper extends TrackerReact(Component) {                
    render() {    
        if (Geolocation.latLng() == null) {
            return (
                <span>Determining location...</span>
            )
        }

        return (
            <div>
                <h1>Reports</h1>
                <ReportsNearby latLng={Geolocation.latLng()} />
            </div>
        )
    }
}

ReportsNearby.jsx

import React, {Component} from "react";
import TrackerReact from "meteor/ultimatejs:tracker-react";
import ReportSingle from "./ReportSingle.jsx";
import NearbyMap from "../maps/NearbyMap.jsx"

export default class ReportsNearby extends TrackerReact(Component) {    
    constructor(props) {
        super(props);
        this.state = {
            subscription: {
                reports: Meteor.subscribe("nearbyReports", 5, props.latLng)
            }
        }
    }

    componentWillUnmount() {
        this.state.subscription.reports.stop();
    }

    _reports() {
        return Reports.find().fetch();
    }

    render() {
        console.log(this._reports()); // this is empty - why???
        return (
            <div>
                <ul>
                    {this._reports().map((report, index)=> {
                        return <ReportSingle key={report._id}
                                             report={report}
                    })}
                </ul>
            </div>
        )
    }
}

ReportSingle.jsx

import React, {Component} from 'react';

export default class ReportSingle extends Component {        
    render() {    
        return (
            <li>
                <a href={`/report/${this.props.report._id}`}>
                    {this.props.report.category}<br/>
                    {this.props.report.description}<br/>
                    {this.props.report.status}
                </a>
            </li>
        )
    }
}

routes.jsx

import React from "react";
import {mount} from "react-mounter";
import {MainLayout} from "./layouts/MainLayout.jsx";
import ReportsWrapper from "./reports/ReportsWrapper.jsx";
import Settings from "./Settings.jsx";
import About from "./About.jsx";

FlowRouter.route('/', {
    action() {
        mount(MainLayout, {
            content: <ReportsWrapper />
        })
    }
});

FlowRouter.route('/settings', {
    action() {
        mount(MainLayout, {
            content: <Settings />
        })
    }
});

FlowRouter.route('/about', {
    action() {
        mount(MainLayout, {
            content: <About />
        })
    }
});

publish.jsx

Meteor.publish("nearbyReports", function (limit, latLng) {
    Reports._ensureIndex({'lngLat': '2dsphere'});
    return Reports.find({
        lngLat: {
            $near: {
                $geometry: {
                    type: "Point",
                    coordinates: [latLng.lng, latLng.lat]
                },
                $minDistance: 0,
                $maxDistance: 3218.69 // this is 2 miles in meters
            }
        }
    }, {
        sort: {createdAt: -1},
        limit: limit,
        skip: 0
    });
});

I ended up getting this working by adding the following code to ReportsWrapper.jsx . I think that ReportsNearby was not getting the latLng prop as expected, even though I had console logged it to verify.

tl;dr Use a timer interval to make sure your app has received the location.

constructor () {
    super();
    this.state = {
        handle: null,
        latLng: Geolocation.latLng()
    }
}

componentDidMount() {
    if (this.state.latLng != null) {
        return
    }

    // Attempt to reload the location if it was not found. do this because the device 
    // location is not immediately available on app start
    this.state.handle = Meteor.setInterval(()=> {
        if (Geolocation.latLng() != null) {
            this.setState({latLng: Geolocation.latLng()}); // Setting the state will trigger a re-render
            Meteor.clearInterval(this.state.handle); // Stop the interval function
        }
    }, 500)
}

componentWillUnmount() {
    // Make sure interval is stopped
    Meteor.clearInterval(this.state.handle);
}

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