Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions packages/react-meteor-data/useTracker.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
/* global Meteor, Package, Tracker */
import React, { useState, useEffect, useRef } from 'react';
import { Tracker } from 'meteor/tracker';
import { Meteor } from 'meteor/meteor';

// Use React.warn() if available (should ship in React 16.9).
const warn = React.warn || console.warn.bind(console);

// Warns if data is a Mongo.Cursor or a POJO containing a Mongo.Cursor.
function checkCursor(data) {
let shouldWarn = false;
if (Package.mongo && Package.mongo.Mongo && data && typeof data === 'object') {
if (data instanceof Package.mongo.Mongo.Cursor) {
shouldWarn = true;
}
else if (Object.getPrototypeOf(data) === Object.prototype) {
} else if (Object.getPrototypeOf(data) === Object.prototype) {
Object.keys(data).forEach((key) => {
if (data[key] instanceof Package.mongo.Mongo.Cursor) {
shouldWarn = true;
Expand All @@ -18,8 +19,6 @@ function checkCursor(data) {
}
}
if (shouldWarn) {
// Use React.warn() if available (should ship in React 16.9).
const warn = React.warn || console.warn.bind(console);
warn(
'Warning: your reactive function is returning a Mongo cursor. '
+ 'This value will not be reactive. You probably want to call '
Expand Down Expand Up @@ -49,8 +48,6 @@ function areHookInputsEqual(nextDeps, prevDeps) {

if (!Array.isArray(nextDeps)) {
if (Meteor.isDevelopment) {
// Use React.warn() if available (should ship in React 16.9).
const warn = React.warn || console.warn.bind(console);
warn(
'Warning: useTracker expected an dependency value of '
+ `type array but got type of ${typeof nextDeps} instead.`
Expand All @@ -76,10 +73,11 @@ function areHookInputsEqual(nextDeps, prevDeps) {

let uniqueCounter = 0;

function useTracker(reactiveFn, deps) {
function useTracker(reactiveFn, deps, cleanup) {
const previousDeps = useRef();
const computation = useRef();
const trackerData = useRef();
const cleanupRef = useRef();

const [, forceUpdate] = useState();

Expand All @@ -88,6 +86,9 @@ function useTracker(reactiveFn, deps) {
computation.current.stop();
computation.current = null;
}
if (cleanupRef.current) {
cleanupRef.current();
}
};

// this is called like at componentWillMount and componentWillUpdate equally
Expand All @@ -106,7 +107,7 @@ function useTracker(reactiveFn, deps) {
Tracker.autorun((c) => {
if (c.firstRun) {
const data = reactiveFn();
Meteor.isDevelopment && checkCursor(data);
if (Meteor.isDevelopment) checkCursor(data);

// store the deps for comparison on next render
previousDeps.current = deps;
Expand All @@ -133,13 +134,16 @@ function useTracker(reactiveFn, deps) {
));
}

// NOTE: Make sure to set cleanupRef AFTER a possible dispose invokes the last one, because
// when/if deps change, we'll likely have a new cleanup method comint with it. So we want
// to invoke the last current one before we reset it.
cleanupRef.current = cleanup;

// stop the computation on unmount only
useEffect(() => {
if (Meteor.isDevelopment
&& deps !== null && deps !== undefined
&& !Array.isArray(deps)) {
// Use React.warn() if available (should ship in React 16.9).
const warn = React.warn || console.warn.bind(console);
warn(
'Warning: useTracker expected an initial dependency value of '
+ `type array but got type of ${typeof deps} instead.`
Expand All @@ -154,8 +158,8 @@ function useTracker(reactiveFn, deps) {

// When rendering on the server, we don't want to use the Tracker.
// We only do the first rendering on the server so we can get the data right away
function useTracker__server(reactiveFn, deps) {
function useTrackerServer(reactiveFn) {
return reactiveFn();
}

export default (Meteor.isServer ? useTracker__server : useTracker);
export default (Meteor.isServer ? useTrackerServer : useTracker);