我对如何使它工作感到困惑。我有三个组件-ReportsWrapper,ReportsNearby和ReportSingle:

1.)ReportsWrapper获取设备位置数据,然后调用ReportsNear,并将位置作为道具传递

2.)ReportsNearby然后使用该位置填充mongodb中的“报告”集合

3.)“报告”中的每个记录都通过ReportSingle组件呈现

问题是“报告”集合在第一次加载时不会填充页面。页面加载后,客户端上未显示任何数据(来自mongodb的数据)。

如果我导航到其他页面(例如/ about或/ settings),然后返回ReportsWrapper,则该集合似乎已按预期填充,并且为每条记录显示一个ReportSingle。在ReportsWrapper上刷新后,该集合再次为空。

有任何想法吗?

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
    });
});

最佳答案

我最终通过将以下代码添加到ReportsWrapper.jsx来使此工作正常进行。我认为ReportsNearby并未按预期获得latLng道具,即使我已将控制台记录下来以进行验证。

tl; dr使用计时器间隔来确保您的应用已收到该位置。

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);
}

10-08 04:06