Correct use of Tracker in react native component?


#1

Hi everyone, I’m having some trouble finding use cases I can understand for Tracker in react native. I am currently using the https://www.npmjs.com/package/@socialize/react-native-meteor package. Currently my component looks like this:

export default class Home extends Component {

    state = { 
        loggedIn: Meteor.userId(), // check if user is logged in, initial state
    };

    render() {........

but soon realized it wasn’t reactive in finding if user was logged in - especially when I call ’ Meteor.logoutOtherClients();’

I know I’m supposed to use Tracker, but im not sure what the correct way of implementing it is? Do I put it in a componentDidMount() ? I would like to make the state reactive so I can show a particular page or not.

Thank you in advance

EDIT: Or should I get rid of the ‘export’ and instead put it inside (found from example):

export default createContainer( () => {
//Tracker Here
  Meteor.subscribe('getAllNumbers')
  return {
    phoneNumbers: Meteor.collection('phoneNumbers').find({})
  }
}, App) 

#2

Working with:

export default withTracker(params=>{
  return {
            loggedIn: Meteor.userId(),
  };
})(App);

#3

A cleaner variant is now allowed by using Hooks and functional components, thus allowing you to delete those frankly annoying HOC component wrappers.

You define this function once:

import { Tracker } from 'meteor/tracker';
import { useState, useEffect, useCallback } from 'react';

export default function withTracker(reactiveFn, dependencies) {
    const [trackerData, setTrackerData] = useState(null);
    const callback = useCallback(reactiveFn, dependencies);

    useEffect(() => {
        let computation;
        Tracker.nonreactive(() => {
        computation = Tracker.autorun(() => setTrackerData(callback()));
        });
        return () => computation.stop();
    }, [callback]);

    return trackerData;
}

And then use it in your component like this:

import React, { useState } from 'react';
import withTracker from './withTracker';

function Home(props) {

  const [otherStateValue, setOtherStateValue] = useState('foo');
  
  const loggedIn = withTracker(() => !!Meteor.userId());
  const phoneNumbers = withTracker(props => {
    Meteor.subscribe('phonenumbers.by_user_id', props.userId);
    return PhoneNumbers.find({}).fetch();
  }, [props.userId]);
  return <div>
             {loggedIn ? {dosomethingwith(phoneNumbers) : 'NotLoggedIn!'}
         </div>;
}

Taken from here: React Hooks - state and lifecycle methods without a class (React 16.7.0-alpha)


#4

@rhywden : That code you posted was an early attempt, the actual PR for react-meteor-data has a safer version.

Also, by convention react hooks are named useXxx() - this applies to the ones that ship with react (useState, useEffect…), and to custom ones you build on top of them.
withTracker() is more the name of a HOC, and useTracker() more the name of a hook.


#5

Could you maybe post the cleaned-up version? Because I can’t make heads or tails out of the PR what with the various additions and subtractions?

I really don’t need the fallback to HOC :wink:


#6

I don’t really feel like copy/pasting the code of an ongoing PR all over the place :wink:
But you can simply grab the content of the useTracker.js file at https://github.com/meteor/react-packages/pull/262/files


#7

Thank you for that. Just one quick question, though:

How would one use useTracker in case of no needed exterior dependencies on a prop? Like, for example, getting all users (with the proper publication server-side, of course!)? Would it look like this?

const users = useTracker(() => {
        Meteor.subscribe('all_users');
        return Meteor.users.find({}).fetch();
    },[]);

#8

Yep, sounds correct.