Fred J. Fred J. - 3 months ago 16
React JSX Question

Meteor Export collection to React component

This Meteor code fails to display the data from the mongo collection

CarsCol
in the browser.

What am I doing wrong? Thanks



// /imports/api/collections.js
export const CarsCol = new Mongo.Collection('carsCol');


// /imports/ui/myList.jsx
import React from 'react';

export const ListItems = ({listItems}) => { //<---- {listItems} undefined
if (listItems && listItems.length > 0) {
return (
<ol>
{listItems.map((item) => (
<li key={item._id}>{item.car}</li>
))}
</ol>
);
} else {
return (
<p>No cars yet!</p> //<------------ shows in browser
);
}
};


// /client/cars.js
import React from 'react';
import ReactDOM from 'react-dom';
import { composeWithTracker } from 'react-komposer';
import { ListItems } from '../imports/ui/myList.jsx';
import { CarsCol } from '../imports/api/collections.js';

const composer = (props, onData) => {
const sub = Meteor.subscribe('carsCol');
if (sub.ready()) {
const cars = CarsCol.find().fetch();
onData(null, {cars});
}
};

const Container = composeWithTracker(composer) (ListItems);
ReactDOM.render(<Container />, document.getElementById('react-root'));


enter image description here

Answer

Very familiar problem. Try to pass reference to collection instead of fetched data via props to the component, like this:

// /imports/api/collections.js
export const CarsCol = new Mongo.Collection('carsCol');


// /imports/ui/myList.jsx
import React from 'react';

export const ListItems = ({cars}) => {
  const listItems = cars.find().fetch(); // <- fetching data from a collection received as a prop right here

  if (listItems && listItems.length > 0) {
    return (
      <ol>
        {listItems.map((item) => (
          <li key={item._id}>{item.car}</li>
        ))}
      </ol>
    );
  } else {
    return (
      <p>No cars yet!</p>   //<------------ shows in browser
    );
  }
};


// /client/cars.js
import React from 'react';
import ReactDOM from 'react-dom';
import { composeWithTracker } from 'react-komposer';
import { ListItems } from '../imports/ui/myList.jsx';
import { CarsCol } from '../imports/api/collections.js';

const composer = (props, onData) => {
  const sub = Meteor.subscribe('carsCol');
  if (sub.ready()) {
    onData(null, {
      cars: CarsCol // <- now the "cars" prop is the collection
    });
  }
};

const Container = composeWithTracker(composer) (ListItems);
ReactDOM.render(<Container />, document.getElementById('react-root'));

I believe that should work, although I'm having strong feeling that you didn't share 100% of the code involved. But hopefully the idea is clear: when subscription is ready, you pass the collection itself, not the data fetched from it, via props, and then perform fetching within the component itself. This way, you'll also preserve reactivity, e.g. when collection is updated, the component will be updated (rendered).