Unable to fetch users in React


#1

I want to create a table to display all my users. I use the account-ui package of Meteor to create new users.

However, It simply returns an empty object when I call my users in my React component. Is there something I forgot ? like an import maybe ?

imports/api/users.js is used to Publish:

import { Meteor } from 'meteor/meteor';

if (Meteor.isServer) {
    Meteor.publish('users', function() {
        return Meteor.users.find({});
    })
}

then I call my component and make use of withTracker in which I subscribe:

import React from 'react';
import { Mongo } from 'meteor/mongo'
import { withTracker } from 'meteor/react-meteor-data';

class CollectionTable extends React.Component {

  render() {

    return (
      <table className="table table-hover table-responsive">
        <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col">First</th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead>
        <tbody>
          {this.props.users.map(u => {
          <tr>
            <th scope="row">{u._id}</th>
            <td>{u.profile.firstname}</td>
            <td>{u.profile.lastname}</td>
            <td>{u.profile.phonenumber}</td>
          </tr>
          })}
        </tbody>
      </table>
    );
  }
}

export default withTracker(() => {
  Meteor.subscribe('users');
  return {
    users: Meteor.users.find().fetch()
  };
})(CollectionTable);

#2

You have to wait until the subscription is ready.

export default withTracker(() => {
  const sub = Meteor.subscribe('users');
  if (sub.ready()) {
    return {
      users: Meteor.users.find().fetch()
    };
  }
  return { users: [] };
})(CollectionTable);

#3

hi minhna,

Thank you very much for your help,

So I added your suggestion but it does not seem to change anything. Just to observe the ouput, I ran this:

  componentDidMount() {
    console.log(this.props.users)
  }

that prints an empty array. Don’t know why :frowning:


#4

OK so I don’t know why this now works but I solved it doing this:

import React from 'react';
import { Mongo } from 'meteor/mongo'
import { withTracker } from 'meteor/react-meteor-data';

export class CollectionTable extends React.Component {

componentWillReceiveProps(newProps) {
  console.log(newProps); // i get the right data!
  console.log(this.props); // empty array >_<
}

  renderUsers() {
      return this.props.users.map(u => (
          <tr key={u._id}>
            <th scope="row">{u._id}</th>
            <td>{u.profile.firstname}</td>
            <td>{u.profile.lastname}</td>
            <td>{u.profile.phonenumber}</td>
          </tr>
          ));
  }
  render() {

    return (
      <table className="table table-hover table-responsive">
        <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col">First</th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead>
        <tbody>
          {this.renderUsers()}
        </tbody>
      </table>
    );
  }
}

export default withTracker(() => {
  const sub = Meteor.subscribe('users');
  if (sub.ready()) {
    console.log(Meteor.users.find().fetch());
    return {
      users: Meteor.users.find().fetch()
    };
  }
  return { users: [] };
})(CollectionTable);

I left my console.log for debugging purposes if ever someone can explain why this.propsgives an empty array, because it is still a mystery for me.

It works perfectly though !


#5

At first, when componentDidMount called, the users props is empty because the subscription has not ready yet.
After that, when the subscription ready, the users props changed, componentWillReceiveProps called with new (updated) props, and the render method will be called (again) after that.


#6

Do not use componentWillReceiveProps as it is marked as deprecated (to be removed in React 17). In this case, use getDerivedStateFromProps instead