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

A valid React element (or null) must be returned

This Meteor React code is producing browser console error:


Warning: ListItems(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.


Exception from Tracker recompute function:

Any idea why? Thanks

//myList.jsx

import React from 'react';

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

export const ListItems = ({listItems}) => {
<ol>{renderIfData(listItems)}</ol>
};


//cars.jsx

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

Everything looks nice except this part:

return listItems.map((item) => {
  return <li key={item._id}>{item.car}</li>;
});

The result of this operation is an array of elements, and React discourages it with exactly the kind of error you're receiving. In fact, in React 16, they promise to allow this, but you're likely using version 15. Anyway, I'd recommend returning a single root element everywhere, so the whole thing would look like

//myList.jsx

import React from 'react';

export const ListItems = ({listItems}) => {
  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>
    );
  }
};


//cars.jsx

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'));