与GraphQL反应:TypeError:解析不是函数

时间:2019-02-13 20:54:22

标签: reactjs .net-core graphql apollo react-apollo

我当前正尝试用对graphql端点的调用来替换我的宁静调用,以从服务器检索我的所有articles。我已经用GraphiQL测试了以下查询,它返回了预期的数据。我还使用fiddler手动将其发布到了端点,并且它按预期运行。我的问题是尝试使用Apollo从react组件调用终结点。

我当前收到以下错误:

TypeError: parse is not a function

我的graphql查询返回的数据示例:

{
  "data": {
    "articles": [
      {
        "id": 1,
        "description": "desc1"
      },
      {
        "id": 2,
        "description": "desc2"
      }
    ]
  }
}

和完整的组件:

import React, { Component } from 'react';
import { Glyphicon } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
import { Query } from "react-apollo";
import gql from "graphql-tag";

export class ArticlesIndex extends Component {
  displayName = ArticlesIndex.name

  constructor(props) {
    super(props);
    this.state = { articles: [], loading: true };
  }

  componentDidMount () {
      <Query
        query={gql`
        query GetArticleData {
          articles {
            id
            description
          }
        }
        `}
      >
    {({ loading, error, data }) => {
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error :(</p>;

        console.log(data.articles);
        this.setState({articles: data.articles, loading: false});
    }}
      </Query>
  }

  renderArticlesTable = articles => {
    return (
      <table className='table'>
        <thead>
          <tr>
            <th>Id</th>
            <th>Title</th>
            <th>Description</th>
            <th>Edit</th>
            <th>Delete</th>
          </tr>
        </thead>
        <tbody>
          {articles.map(article =>
            <tr key={article.id}>
              <td>{article.id}</td>
              <td>{article.title}</td>
              <td dangerouslySetInnerHTML={{ __html: article.description }}></td>
              <td>
                <LinkContainer to={'/articles/edit/' + article.id}>
                    <Glyphicon glyph='edit' />
                </LinkContainer>
            </td>
            <td onClick={(e) => this.deleteArticle(e, article.id) }>
              <Glyphicon glyph='trash' />
            </td>
            </tr>
          )}
        </tbody>
      </table>
    );
  }

  render() {
    let contents = this.state.loading
      ? <p><em>Loading...</em></p>
      : this.renderArticlesTable(this.state.articles);

    return (
      <div>
        <h1>Articles</h1>
        <LinkContainer to={'/articles/create'}>
          <button type="button" className="btn btn-default">New Article</button> 
        </LinkContainer>
        {contents}
      </div>
    );
  }

  deleteArticle(event, id) { 
    fetch('https://localhost:44360/api/articles/' + id, {  
        method: 'DELETE'
    }).then((response) => response.json())  
        .then((responseJson) => {  
            var deletedId = responseJson.id;

        this.setState({
          articles: this.state.articles.filter(function( obj ) {
            return obj.id !== deletedId;
          })
        });

    })  
  }
}

请注意,我的断点未在服务器端命中,并且未对服务器发出任何请求。

App.js中,我按如下所示设置了ApolloClientApolloProvider

client = new ApolloClient({
    uri: "https://localhost:44360/graphql"
  });

  render() {
    return (
      <ApolloProvider client={this.client}>
        <Layout>
          <Route exact path='/' component={Home} exact={true} />
          <Route path='/articles' component={ArticlesIndex} exact={true} />
          <Route path='/articles/create' component={ArticlesCreate} exact={true} />
          <Route path='/articles/edit/:id' component={ArticlesEdit} exact={true} />
        </Layout>
      </ApolloProvider>
    );
  }

为什么会这样,我该如何克服呢?

编辑:正如我在其他地方看到的建议,我将graphql npm软件包降级为版本0.12.3,这在控制台或其他方面均未导致任何错误,但屏幕停留在Loading...仍然没有任何请求发送到服务器。

编辑2:我现在尝试了列出的所有here解决方法,并在尝试更改webpack配置的建议后,页面不会像以前一样出错,但是仍然没有请求发送到服务器,并且{ {1}}永远停留在页面上。我的Loading...函数中的断点被击中,但似乎什么也没发生。

编辑3:如果我用下面的静态调用替换了graphql调用以获取数据,则一切正常,但是该项目的目的是探索对graphql的反应。正常运行且我要替换的宁静呼叫如下:

componentDidMount

1 个答案:

答案 0 :(得分:2)

您在componentDidMount中使用了JSX,相反,您可以执行this.props.client.query({query: GET_ARTICLES}),我对其进行了测试,它可以正常工作。

将您的articles/index.js更改为

import React, { Component } from "react";
import { Glyphicon } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { Query, withApollo } from "react-apollo";
import gql from "graphql-tag";

const GET_ARTICLES = gql`
query GetArticleData {
    articles {
    id
    description
    }
}
`;
class ArticlesIndex extends Component {
state = { articles: [], loading: true };
displayName = ArticlesIndex.name;

componentDidMount = () => {
    const { client } = this.props;
    client
    .query({ query: GET_ARTICLES })
    .then(({ data: { articles } }) => {
        if (articles) {
        this.setState({ loading: false, articles });
        }
    })
    .catch(err => {
        console.log("err", err);
    });
};

renderArticlesTable = articles => {
    return (
    <table className="table">
        <thead>
        <tr>
            <th>Id</th>
            <th>Title</th>
            <th>Description</th>
            <th>Edit</th>
            <th>Delete</th>
        </tr>
        </thead>
        <tbody>
        {articles.map(article => (
            <tr key={article.id}>
            <td>{article.id}</td>
            <td>{article.title}</td>
            <td dangerouslySetInnerHTML={{ __html: article.description }} />
            <td>
                <LinkContainer to={"/articles/edit/" + article.id}>
                <Glyphicon glyph="edit" />
                </LinkContainer>
            </td>
            <td onClick={e => this.deleteArticle(e, article.id)}>
                <Glyphicon glyph="trash" />
            </td>
            </tr>
        ))}
        </tbody>
    </table>
    );
};

render() {
    let contents = this.state.loading ? (
    <p>
        <em>Loading...</em>
    </p>
    ) : (
    this.renderArticlesTable(this.state.articles)
    );

    return (
    <div>
        <h1>Articles</h1>
        <LinkContainer to={"/articles/create"}>
        <button type="button" className="btn btn-default">
            New Article
        </button>
        </LinkContainer>
        {contents}
    </div>
    );
}

deleteArticle(event, id) {
    fetch("https://localhost:44360/api/articles/" + id, {
    method: "DELETE"
    })
    .then(response => response.json())
    .then(responseJson => {
        var deletedId = responseJson.id;

        this.setState({
        articles: this.state.articles.filter(function(obj) {
            return obj.id !== deletedId;
        })
        });
    });
}
}

export default withApollo(ArticlesIndex);

将您的App.js更改为

import React, { Component } from "react";
import { Route } from "react-router";
import { Layout } from "./components/Layout";
import { Home } from "./components/Home";
import ArticlesIndex from "./components/articles/Index";
import { ArticlesCreate } from "./components/articles/Create";
import { ArticlesEdit } from "./components/articles/Edit";
import { ApolloProvider } from "react-apollo";
import ApolloClient from "apollo-boost";

export default class App extends Component {
  displayName = App.name;

  client = new ApolloClient({
    uri: "https://localhost:44360/graphql"
  });

  render() {
    return (
      <ApolloProvider client={this.client}>
        <Layout>
          <Route exact path="/" component={Home} exact={true} />
          <Route path="/articles" component={ArticlesIndex} exact={true} />
          <Route
             path="/articles/create"
             component={ArticlesCreate}
             exact={true}
          />
          <Route
            path="/articles/edit/:id"
            component={ArticlesEdit}
            exact={true}
          />
        </Layout>
      </ApolloProvider>
     );
   }
}

问题是您在ComponentDidMount内使用了JSX,这在react中不受支持,为了在生命周期方法中使用查询,您应该使用withApollo包装该组件,将客户添加到道具(因此export default withApollo(ArticlesIndex);)中,然后可以在this.props.client.query中进行componentDidMount,然后可以设置状态。