react-native-meteor withTracker 不必要地重复重新订阅
react-native-meteor withTracker resubscribing repeatedly ever second unnecessarily
下面的 screen/component 工作正常,但是 console.log 语句(在 withTracker 部分结束文件末尾)每秒(永远)重复一次,表明订阅正在一遍又一遍地重新运行无缘无故 - 我知道 server/DB 上的数据没有变化,因为我是唯一登录到该应用程序的用户。
import React, { Component } from "react";
import { View, Text } from "react-native";
import { Button } from "native-base";
import Meteor, { withTracker } from "react-native-meteor";
import moment from "moment";
import LoadingScreen from "../components/LoadingScreen";
class JobDetailsScreen extends Component {
constructor(props) {
super(props);
posterInfo = this.props.navigation.state.params.posterInfo;
this.state = {
posterUsername: posterInfo.firstName + " " + posterInfo.surname.charAt(0),
posterProfilePicUrl: posterInfo.profilePicUrl
};
}
render() {
if (!this.props.myShiftRequestReady) {
return <LoadingScreen />;
}
const job = this.props.job;
return (
<View>
<H3>{job.type + ": $" + job.ratePerHour + "/hr"}</H3>
<Image source={{uri: this.state.posterProfilePicUrl}}/>
<Text>
{this.state.posterUsername + moment(job.datePosted).fromNow()}
</Text>
<Text>{job.location}</Text>
<Text>
{moment(job.start).fromNow()
+ moment(job.end).from(moment(job.start), true)}
</Text>
<Text> {moment(job.start).format("DD/MM/YY h:mm a")
+ moment(job.end).format("DD/MM/YY h:mm a")} </Text>
<Text>{job.summary}</Text>
<Button
onPress={() => {
if (!this.props.myShiftRequest) {
Meteor.call("ShiftRequests.add", job, (err, res) => {});
return;
}
if (!this.props.myShiftRequest.accepted) {
Meteor.call("ShiftRequests.remove", job._id, (err, res) => {});
}
}}
>
<Text>
{!this.props.myShiftRequest
? "Request shift"
: !this.props.myShiftRequest.accepted
? "Cancel Request"
: this.props.myShiftRequest.didNotTurnUp
? "You did not turn up for this shift"
: job.finshed
? "Rate employer"
: "Shift in progress"}
</Text>
</Button>
</View>
);
}
}
const container = withTracker(params => {
const jobId = params.navigation.state.params.jobId;
const srHandle = Meteor.subscribe("myShiftRequestForJob", jobId);
console.log("subscribing myShiftRequestForJob with jobId " + jobId);
return {
myShiftRequestReady: srHandle.ready(),
myShiftRequest: Meteor.collection("shift_requests").findOne({
userId: Meteor.userId(),
jobId: jobId
}),
job: Meteor.collection("jobs").findOne({ _id: jobId })
};
})(JobDetailsScreen);
export default container;
我最终将订阅移出了 withTracker。事实上 - 我认为 https://github.com/inProgress-team/react-native-meteor 的文档示例在演示此方法时是错误的,因为它可能导致订阅的无限循环:
- 订阅的数据发生变化,导致 withTracker 代码重新运行
- 但是在withTracker里面,我们又开始订阅了!这会导致无功值发生变化(可能)
- 在后台无限循环,消耗网络和内存以及 CPU 资源
正确的方法是在componentDidMount()中订阅数据,本文建议:https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
修改后的代码:
import React, { Component } from "react";
import { View } from "react-native";
import Meteor, { withTracker } from "react-native-meteor";
import LoadingScreen from "../components/LoadingScreen";
class JobDetailsScreen extends Component {
constructor(props) {
super(props);
posterInfo = this.props.navigation.state.params.posterInfo;
this.state = {
posterUsername: posterInfo.firstName + " " + posterInfo.surname.charAt(0),
posterProfilePicUrl: posterInfo.profilePicUrl
};
}
render() {
if (!this.props.myShiftRequest || !this.props.job) {
return <LoadingScreen />;
}
return (
<View>
...
<ComponentToDisplay/>
...
</View>
);
}
componentDidMount() {
const jobId = this.props.navigation.state.params.jobId;
const srHandle = Meteor.subscribe("myShiftRequestForJob", jobId);
__DEV__
? console.log("subscribing myShiftRequestForJob with jobId " + jobId)
: null;
}
}
const container = withTracker(params => {
const jobId = params.navigation.state.params.jobId;
return {
myShiftRequest: Meteor.collection("shift_requests").findOne({
userId: Meteor.userId(),
jobId: jobId
}),
job: Meteor.collection("jobs").findOne({ _id: jobId })
};
})(JobDetailsScreen);
container.navigationOptions = {
title: "Shift details"
};
export default container;
下面的 screen/component 工作正常,但是 console.log 语句(在 withTracker 部分结束文件末尾)每秒(永远)重复一次,表明订阅正在一遍又一遍地重新运行无缘无故 - 我知道 server/DB 上的数据没有变化,因为我是唯一登录到该应用程序的用户。
import React, { Component } from "react";
import { View, Text } from "react-native";
import { Button } from "native-base";
import Meteor, { withTracker } from "react-native-meteor";
import moment from "moment";
import LoadingScreen from "../components/LoadingScreen";
class JobDetailsScreen extends Component {
constructor(props) {
super(props);
posterInfo = this.props.navigation.state.params.posterInfo;
this.state = {
posterUsername: posterInfo.firstName + " " + posterInfo.surname.charAt(0),
posterProfilePicUrl: posterInfo.profilePicUrl
};
}
render() {
if (!this.props.myShiftRequestReady) {
return <LoadingScreen />;
}
const job = this.props.job;
return (
<View>
<H3>{job.type + ": $" + job.ratePerHour + "/hr"}</H3>
<Image source={{uri: this.state.posterProfilePicUrl}}/>
<Text>
{this.state.posterUsername + moment(job.datePosted).fromNow()}
</Text>
<Text>{job.location}</Text>
<Text>
{moment(job.start).fromNow()
+ moment(job.end).from(moment(job.start), true)}
</Text>
<Text> {moment(job.start).format("DD/MM/YY h:mm a")
+ moment(job.end).format("DD/MM/YY h:mm a")} </Text>
<Text>{job.summary}</Text>
<Button
onPress={() => {
if (!this.props.myShiftRequest) {
Meteor.call("ShiftRequests.add", job, (err, res) => {});
return;
}
if (!this.props.myShiftRequest.accepted) {
Meteor.call("ShiftRequests.remove", job._id, (err, res) => {});
}
}}
>
<Text>
{!this.props.myShiftRequest
? "Request shift"
: !this.props.myShiftRequest.accepted
? "Cancel Request"
: this.props.myShiftRequest.didNotTurnUp
? "You did not turn up for this shift"
: job.finshed
? "Rate employer"
: "Shift in progress"}
</Text>
</Button>
</View>
);
}
}
const container = withTracker(params => {
const jobId = params.navigation.state.params.jobId;
const srHandle = Meteor.subscribe("myShiftRequestForJob", jobId);
console.log("subscribing myShiftRequestForJob with jobId " + jobId);
return {
myShiftRequestReady: srHandle.ready(),
myShiftRequest: Meteor.collection("shift_requests").findOne({
userId: Meteor.userId(),
jobId: jobId
}),
job: Meteor.collection("jobs").findOne({ _id: jobId })
};
})(JobDetailsScreen);
export default container;
我最终将订阅移出了 withTracker。事实上 - 我认为 https://github.com/inProgress-team/react-native-meteor 的文档示例在演示此方法时是错误的,因为它可能导致订阅的无限循环:
- 订阅的数据发生变化,导致 withTracker 代码重新运行
- 但是在withTracker里面,我们又开始订阅了!这会导致无功值发生变化(可能)
- 在后台无限循环,消耗网络和内存以及 CPU 资源
正确的方法是在componentDidMount()中订阅数据,本文建议:https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
修改后的代码:
import React, { Component } from "react";
import { View } from "react-native";
import Meteor, { withTracker } from "react-native-meteor";
import LoadingScreen from "../components/LoadingScreen";
class JobDetailsScreen extends Component {
constructor(props) {
super(props);
posterInfo = this.props.navigation.state.params.posterInfo;
this.state = {
posterUsername: posterInfo.firstName + " " + posterInfo.surname.charAt(0),
posterProfilePicUrl: posterInfo.profilePicUrl
};
}
render() {
if (!this.props.myShiftRequest || !this.props.job) {
return <LoadingScreen />;
}
return (
<View>
...
<ComponentToDisplay/>
...
</View>
);
}
componentDidMount() {
const jobId = this.props.navigation.state.params.jobId;
const srHandle = Meteor.subscribe("myShiftRequestForJob", jobId);
__DEV__
? console.log("subscribing myShiftRequestForJob with jobId " + jobId)
: null;
}
}
const container = withTracker(params => {
const jobId = params.navigation.state.params.jobId;
return {
myShiftRequest: Meteor.collection("shift_requests").findOne({
userId: Meteor.userId(),
jobId: jobId
}),
job: Meteor.collection("jobs").findOne({ _id: jobId })
};
})(JobDetailsScreen);
container.navigationOptions = {
title: "Shift details"
};
export default container;