0

I have this test relay-starter-kit project with an autocomplete search form that renders quotes to the browser. When I use the search form, I get an error in the browser saying "app.js:8284 Uncaught TypeError: Cannot read property 'edges' of undefined". I cant understand why its populating the search fields the first time but not on typing in the search form. Of note, if you hard code the searchTerm variable, it will render the search results. In other words, It can read the edges when its hard coded. Any guidance on this would be great. Thanks.

The schema is here This is the component that the valid graphql query for the search term wont render to.

    import React from 'react';
    import Relay from 'react-relay';
    import { debounce } from 'lodash';
    import SearchForm from '../search-form';
    import Quote from '../quote';

    class App extends React.Component {
        constructor(props) {
        super(props)
        this.search = debounce(this.search.bind(this), 300)
      }
      search(searchTerm) {
        this.props.relay.setVariables({ searchTerm });
      }

      render() {
        return (
          <div className="quotes-library">
            <SearchForm searchAction={this.search} />
            <div className="quotes-list">
              {this.props.viewer.quotes.edges.map(edge =>
                <Quote key={edge.node.id} quote={edge.node} />
              )}
            </div>
          </div>
        )
      }
    }

    export default Relay.createContainer(App, {
      initialVariables: {
        searchTerm: '',
      },
      fragments: {
        viewer: () => Relay.QL`
          fragment on User {
                quotes(first:100, searchTerm: $searchTerm) {
                    edges {
                        node {
                            id
                            ${Quote.getFragment('quote')}
                        }
                    }
                }
            }
        `,
      },
    });

Update: This is the query as shown in Chrome DevTools network tab. Note the 'p' input to the search form is being queried.

    query App_ViewerRelayQL($id_0:ID!) {
  node(id:$id_0) {
    ...F2
  }
}
fragment F0 on Quote {
  id,
  likesCount
}
fragment F1 on Quote {
  text,
  author,
  id,
  ...F0
}
fragment F2 on User {
  _quotes3UfnML:quotes(first:100,searchTerm:"pri") {
    edges {
      node {
        id,
        ...F1
      },
      cursor
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage
    }
  },
  id
}

Adding console.log to render() shows the searchTerm input:

 app.js:17
   {
    "viewer": {
        "__dataID__": "VXNlcjox",
        "__status__": 4
    },
    "relay": {
        "pendingVariables": null,
        "route": {
            "name": "AppHomeRoute",
            "params": {},
            "queries": {}
        },
        "variables": {
            "searchTerm": "pri"
        }
    }
}

The following error occurs at line 24 in app.js, which is {this.props.library.quotes.edges.map(edge => <Quote key={edge.node.id} quote={edge.node} /> )}:

app.js:8285 Uncaught TypeError: Cannot read property 'edges' of undefined
    at App.render (app.js:8285)
    at app.js:43197
    at measureLifeCyclePerf (app.js:42476)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (app.js:43196)
    at ReactCompositeComponentWrapper._renderValidatedComponent (app.js:43223)
    at ReactCompositeComponentWrapper._updateRenderedComponent (app.js:43147)
    at ReactCompositeComponentWrapper._performComponentUpdate (app.js:43125)
    at ReactCompositeComponentWrapper.updateComponent (app.js:43046)
    at ReactCompositeComponentWrapper.receiveComponent (app.js:42948)
    at Object.receiveComponent (app.js:35341)

UPDATE 2:

So check this out. I'm doing something wrong with my { ObjectID }. I pulled a user and quote from the db and there is an '_id' but no 'id' property on the object. This is the output:

 > db.users.find({})
{ "_id" : ObjectId("586253169465191cb812066c"), "name" : "me", "id" : ObjectId("586253169465191cb812066c"), "errors" : [ ] }
> db.quotes.find({})
{ "_id" : ObjectId("586693333ff93f3581c0ca05"), "text" : "Hi Prisc", "author" : "H. Jackson Brown", "likesCount" : 24 }
{ "_id" : ObjectId("586693333ff93f3581c0ca06"), "text" : "If opportunity doesn't knock, build a door", "author" : "Milton Berle", "likesCount" : 2 }
{ "_id" : ObjectId("586693333ff93f3581c0ca07"), "text" : "Try to be a rainbow in...", "author" : "Maya Angelou" }

If I log the id from the globalIdFetcher(), the logged id for the Jackson Brown Quote object show two id's as expected but they are both the same and different from the one in the db. Output in console is:

{
    "viewer": {
        "__dataID__": "VXNlcjo=",
        "quotes": {
            "__dataID__": "client:6068631311_first(100),searchTerm()",
            "edges": [
                {
                    "__dataID__": "client:client:6068631311:UXVvdGU6NTg2NjkzMzMzZmY5M2YzNTgxYzBjYTA1",
                    "node": {
                        "__dataID__": "UXVvdGU6NTg2NjkzMzMzZmY5M2YzNTgxYzBjYTA1",
                        "id": "UXVvdGU6NTg2NjkzMzMzZmY5M2YzNTgxYzBjYTA1",
                        "__fragments__": {
                            "1::client": [
                                {
                                    "showLikes": false
                                }
                            ]
                        }
                    }
                },

Any ideas on fixing this syntax?

armand
  • 693
  • 9
  • 29

2 Answers2

0

It's very difficult to solve the problem with the information provided in question. As you requested guidance, here's my suggestions :)

I cant understand why its populating the search fields the first time but not on typing in the search form.

Because Relay fetches the result for the initial value of searchTerm, which is an empty string in your case. You have to deal with this case on the server side (by checking the input searchTerm) and client side (by checking if the current value of searchTerm is empty, for example).

When you type in search form, search() isn't called and searchTerm is not updated. Check SearchForm component.

When I use the search form, I get an error in the browser saying "app.js:8284 Uncaught TypeError: Cannot read property 'edges' of undefined".

Start debugging what the server side returns for quotes field under viewer GraphQL object type. What's the output of db.collection('quotes').find(findParams).toArray() in your schema? In addition, put a console.log(JSON.stringify(this.props, null, 4)) in render() function of App class. Check what you see. You can also inspect the HTTP request and response on the Chrome DevTools Network tab. Filter by graphql.

Ahmad Ferdous
  • 3,351
  • 16
  • 33
  • Very helpful comment as far as sharing your debug process. Thanks. Per post, query was working and returning and taking the search params just not rendering back. Per your suggestion, added, log call to render(). I updated the original question with the output from log call, network query and the error. Anything stand out to you? Incidentally (or not) this work if I change the root query to a const with a type that just resolve the list. Adding the viewer resolving to User field of qoutesConnectionType is where I lost my way. – armand Jan 17 '17 at 21:57
  • What is the response of query that you get on Chrome DevTools network tab? – Ahmad Ferdous Jan 17 '17 at 22:50
  • In the OP, at UPDATE. [status 200](https://gist.github.com/idkjs/f7aafdd575f093e8bf421d84a3de08b1) – armand Jan 17 '17 at 23:12
  • No, that's not what I'm talking about. When you select the request on the left, you'll see sub-tabs like Headers, Preview, Response, Cookies, Timing. Click on Response and tell us what you see. – Ahmad Ferdous Jan 17 '17 at 23:14
  • `{ "data": { "node": {} } }` – armand Jan 17 '17 at 23:35
  • This is the initial load response with initial variable set to empty string:`{ "data": { "viewer": { "id": "VXNlcjox", "_quotes1GESCp": { "edges": [ { "node": { "id": "UXVvdGU6NTg2NjkzMzMzZmY5M2YzNTgxYzBjYTA1", "text": "Hi Prisc", "author": "H. Jackson Brown", "likesCount": 23 }, "cursor": "YXJyYXljb25uZWN0aW9uOjA=" },.....` – armand Jan 17 '17 at 23:50
  • `{ "data": { "node": {} } }` doesn't seem right. What is the request query corresponding to this response? – Ahmad Ferdous Jan 18 '17 at 07:07
  • The request query is what is posted in the OP. – armand Jan 18 '17 at 09:08
  • Screenshot of expanded Request Header: https://gyazo.com/1c675b655d7b4935e130de42acd75031 or https://github.com/idkjs/relay-starter-kit/blob/quotes-refactor/Screen%20Shot%202017-01-18%20at%2010.09.39.png – armand Jan 18 '17 at 09:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/133423/discussion-between-idkjs-and-ahmad-ferdous). – armand Jan 18 '17 at 09:25
0

Solution was to take the Quote type out of the nodeInterface so only running the top level object through the nodeInterface, let relay generate the id for the objectId from the GraphQLID or fromGlobalId as defined in the individual itemType.

armand
  • 693
  • 9
  • 29