Search code examples
reactjsgraphqlapolloreact-apollographcool

Uncaught Error: AllPostsComments.render(): A valid ReactComponent must be returned


So, I'm receiving the following error message when attempting to data from a GraphCool backend:

Uncaught Error: AllPostsComments.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
    at invariant (http://localhost:7770/static/bundle.js:3026:16)
    at ReactCompositeComponentWrapper._renderValidatedComponent (http://localhost:7770/static/bundle.js:9619:157)
    at ReactCompositeComponentWrapper.wrapper [as _renderValidatedComponent] (http://localhost:7770/static/bundle.js:3344:22)
    at ReactCompositeComponentWrapper._updateRenderedComponent (http://localhost:7770/static/bundle.js:9566:37)
    at ReactCompositeComponentWrapper._performComponentUpdate (http://localhost:7770/static/bundle.js:9550:11)
    at ReactCompositeComponentWrapper.updateComponent (http://localhost:7770/static/bundle.js:9479:13)
    at ReactCompositeComponentWrapper.wrapper [as updateComponent] (http://localhost:7770/static/bundle.js:3344:22)
    at ReactCompositeComponentWrapper.receiveComponent (http://localhost:7770/static/bundle.js:9411:11)
    at Object.receiveComponent (http://localhost:7770/static/bundle.js:7586:23)
    at ReactCompositeComponentWrapper._updateRenderedComponent (http://localhost:7770/static/bundle.js:9568:24)
    at ReactCompositeComponentWrapper._performComponentUpdate (http://localhost:7770/static/bundle.js:9550:11)
    at ReactCompositeComponentWrapper.updateComponent (http://localhost:7770/static/bundle.js:9479:13)
    at ReactCompositeComponentWrapper.wrapper [as updateComponent] (http://localhost:7770/static/bundle.js:3344:22)
    at ReactCompositeComponentWrapper.performUpdateIfNecessary (http://localhost:7770/static/bundle.js:9427:13)
    at Object.performUpdateIfNecessary (http://localhost:7770/static/bundle.js:7601:23)
    at runBatchedUpdates (http://localhost:7770/static/bundle.js:8183:22)
    at ReactReconcileTransaction.perform (http://localhost:7770/static/bundle.js:8643:21)
    at ReactUpdatesFlushTransaction.perform (http://localhost:7770/static/bundle.js:8643:21)
    at ReactUpdatesFlushTransaction.perform (http://localhost:7770/static/bundle.js:8140:39)
    at Object.flushBatchedUpdates (http://localhost:7770/static/bundle.js:8201:20)
    at Object.wrapper [as flushBatchedUpdates] (http://localhost:7770/static/bundle.js:3344:22)
    at ReactDefaultBatchingStrategyTransaction.closeAll (http://localhost:7770/static/bundle.js:8709:26)
    at ReactDefaultBatchingStrategyTransaction.perform (http://localhost:7770/static/bundle.js:8656:17)
    at Object.batchedUpdates (http://localhost:7770/static/bundle.js:12680:20)
    at Object.enqueueUpdate (http://localhost:7770/static/bundle.js:8230:23)
    at enqueueUpdate (http://localhost:7770/static/bundle.js:7815:17)
    at Object.enqueueSetState (http://localhost:7770/static/bundle.js:7981:6)
    at GraphQL.ReactComponent.setState (http://localhost:7770/static/bundle.js:17838:17)
    at GraphQL.forceRenderChildren (http://localhost:7770/static/bundle.js:37273:27)
    at Object.next (http://localhost:7770/static/bundle.js:37250:28)
    at http://localhost:7770/static/bundle.js:40174:30
    at Array.forEach (native)
    at Object.next (http://localhost:7770/static/bundle.js:40172:34)
    at http://localhost:7770/static/bundle.js:40625:47
    at http://localhost:7770/static/bundle.js:41065:26
    at Array.forEach (native)
    at http://localhost:7770/static/bundle.js:41062:28
    at Array.forEach (native)
    at QueryManager.broadcastQueries (http://localhost:7770/static/bundle.js:41059:43)
    at QueryManager.broadcastNewStore (http://localhost:7770/static/bundle.js:40458:15)
    at http://localhost:7770/static/bundle.js:41127:45
    at http://localhost:7770/static/bundle.js:75299:17
    at Object.dispatch (http://localhost:7770/static/bundle.js:23161:19)
    at http://localhost:7770/static/bundle.js:40988:30

from the following component:

PhotoGrid.js

import _ from 'lodash';
import React from 'react';
import Photo from './Photo';
import {
  gql,
  graphql,
} from 'react-apollo';

const PhotoGrid = React.createClass({

  handleSubmit(e) {
    e.preventDefault();
    this.props.addItem(this.refs.item.value);
  },

  render() {
    // const posts = this.props.posts;
    const AllPostsComments = ({ data: {loading, error, allPostses }}) => {
      if (loading) {
        return <p>Loading ...</p>;
      }
      if (error) {
        return <p>{error.message}</p>;
      }
      return 
        <div className="photo-grid">
          { allPostses.map( posts => <Photo key={posts.id} i={posts.id} post={posts} /> ) }
        </div>;
    };

    const allPostsCommentsQuery = gql`
      query allPostsCommentsQuery {
        allPostses {
          id
          displaysrc
          caption
          comments {
            id
            posts {
              id
            }
            text
            user
          }
        }
      }
    `;

    const ChannelsListWithData = graphql(allPostsCommentsQuery)(AllPostsComments);
    
    return (
      <ChannelsListWithData />
    );
  }
});

export default PhotoGrid;

which is eventually imported into app.js:

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute } from 'react-router'
import 'babel-polyfill';
import { ApolloProvider, graphql, gql } from 'react-apollo';
import client from './apolloClient';
 
/*
  Import Components
*/
import App from './components/App';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';

/* Import CSS */
import css from  './styles/style.styl';

/* Import our data store */
import store, { history } from './store';

/*
  Error Logging
*/
import Raven from 'raven-js';
import { sentry_url } from './data/config';
if(window) {
  Raven.config(sentry_url).install();
}

/*
  Rendering
  This is where we hook up the Store with our actual component and the router
*/
render(
  <ApolloProvider store={store} client={client}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute component={PhotoGrid} />
        <Route path="/view/:postId" component={Single}></Route>
      </Route>
    </Router>
  </ApolloProvider>,
  document.getElementById('root')
);

What am I overlooking here?


Solution

  • Looks like something with your PhotoGrid component is incorrect. It's also recommended to use React.Component instead of React.createClass and also, it's preferred to wrap the component with graphql outside of the render method. All together this is what you get:

    import _ from 'lodash';
    import React from 'react';
    import Photo from './Photo';
    import {
      gql,
      graphql,
    } from 'react-apollo';
    
    class PhotoGrid extends React.Component {
    
      handleSubmit(e) {
        e.preventDefault();
        this.props.addItem(this.refs.item.value);
      },
    
      render() {
        if (this.props.data.loading) {
          return <p>Loading ...</p>;
        }
        if (this.props.data.error) {
          return <p>{this.props.data.error.message}</p>;
        }
        return (
          <div className="photo-grid">
            { this.props.data.allPostses.map( posts => <Photo key={posts.id} i={posts.id} post={posts} /> ) }
          </div>;
        )
      };
    };
    
    
    const allPostsCommentsQuery = gql`
      query allPostsCommentsQuery {
        allPostses {
          id
          displaysrc
          caption
          comments {
            id
            posts {
              id
            }
            text
            user
          }
        }
      }
    `;
    
    const ChannelsListWithData = graphql(allPostsCommentsQuery)(AllPostsComments);
    
    export default ChannelsListWithData;
    

    You can compare your code to this RN app example or check the RN track in Learn Apollo for more information.