【问题标题】:React with GraphQL: TypeError: parse is not a function与 GraphQL 反应:TypeError: parse is not a function
【发布时间】:2019-07-07 19:43:33
【问题描述】:

我目前正在尝试用对 graphql 端点的调用替换我的 restful 调用,以从服务器检索我的所有 articles。我已经用GraphiQL 测试了以下查询,它返回了预期的数据。我还使用 fiddler 手动发布到端点,它按预期运行。我的问题是尝试使用Apollo 从反应组件调用端点。

我目前收到以下错误:

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 配置的建议后,页面不会像以前一样出错,但是仍然没有请求发送到服务器和 Loading...永远停留在页面上。我的componentDidMount 函数中的断点被击中,但似乎没有发生任何事情。

编辑 3:如果我用以下 restful 调用替换 graphql 调用以获取数据,一切都会正常运行,但该项目的目的是探索与 graphql 的反应。正常运行并且我试图替换的宁静调用如下:

fetch('https://localhost:44360/api/Articles/')
      .then(response => response.json())
      .then(data => {
        this.setState({ articles: data, loading: false });
      });

【问题讨论】:

  • 您是否有架构来检查您编写的查询,我怀疑这是编写它的正确方法,但如果您确实有架构仔细检查。
  • Graphql版本有问题,能分享一下你用的是什么版本吗?你可能需要降级或升级它。
  • @RachidRhafour 我最初使用的是 graphql 版本 14.1.1 并尝试降级到 0.12.3 以解决导致我帖子的“编辑”部分所述行为的问题
  • 我不确定哪个版本可以工作,但我正在使用 Graphql v14.0.2 和 "graphql-tag": "2.10.0" npm 版本是 5.6.0
  • 已更改为您提到的软件包,但仍然出现相同的错误TypeError: parse is not a function 我的用法与您的相同吗?我仍然没有收到任何请求发送到服务器,并且在导航到页面时发生该错误

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


【解决方案1】:

您在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 包装组件,这会将客户端添加到props (因此export default withApollo(ArticlesIndex);),然后你可以在componentDidMount 中做this.props.client.query 然后你可以setState。

【讨论】:

    猜你喜欢
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    相关资源
    最近更新 更多