Реакция с GraphQL: TypeError: синтаксический анализ не является функцией

В настоящее время я пытаюсь заменить свой спокойный вызов для получения всех моих articles с сервера вызовом конечной точки graphql. Я протестировал следующий запрос с помощью 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.info(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 я настроил ApolloClient и ApolloProvider следующим образом:

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... по-прежнему без отправки запроса на сервер.

Обновлено еще раз: теперь я пробовал все обходные пути, перечисленные в здесь, и после попытки изменить конфигурацию веб-пакета страница не будет выдавать ошибку, как раньше, однако запрос по-прежнему не отправляется на сервер, и Loading... навсегда остается на странице. Точки останова в моей функции componentDidMount срабатывают, но, похоже, ничего не происходит.

РЕДАКТИРОВАТЬ 3: Если я заменю вызов graphql для получения данных следующим спокойным вызовом, все будет вести себя как обычно, но целью этого проекта является изучение реакции с помощью graphql. Успокаивающий вызов, который работает правильно и который я пытаюсь заменить, приведен ниже:

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

У вас есть схема для проверки запроса, который вы написали, я сомневаюсь, что это правильный способ написать его, но если у вас есть схема, двойная проверка.

Rachid Rhafour 14.02.2019 03:38

Это проблема с версией Graphql, не могли бы вы поделиться, какую версию вы используете? вам может потребоваться понизить или обновить его.

Rachid Rhafour 14.02.2019 12:00

@RachidRhafour Первоначально я использовал версию graphql 14.1.1 и попытался перейти на версию 0.12.3, чтобы решить проблему, которая привела к поведению, указанному в разделе «ИЗМЕНИТЬ» моего сообщения.

GregH 15.02.2019 14:06

Я не уверен, какая версия может работать, но я использую Graphql v14.0.2 с «graphql-tag»: версия npm «2.10.0» 5.6.0

Rachid Rhafour 15.02.2019 14:21

изменены на пакеты, которые вы упомянули, и все еще получаю ту же ошибку TypeError: parse is not a function мое использование такое же, как ваше? Я все еще не получаю никаких запросов, когда-либо отправленных на сервер, и эта ошибка возникает при переходе на страницу.

GregH 15.02.2019 14:24

можете ли вы иметь этот пример в песочнице кода и поделиться им со мной, чтобы я мог посмотреть?

Rachid Rhafour 15.02.2019 16:16

простой проект, в который он включен, находится по адресу bitbucket.org/greghofman/реакттофакты/src/развитие, он включает в себя базовую часть .net, которая включает в себя graphql. Приложение React находится в ReactToFacts.Client.

GregH 15.02.2019 16:24

Думаю, я нашел почему, дайте мне второй, плз.

Rachid Rhafour 15.02.2019 22:27

проверьте мой ответ, пожалуйста, дайте мне знать, если он работает для вас :)

Rachid Rhafour 15.02.2019 22:48

можешь проверить мой ответ?

Rachid Rhafour 18.02.2019 11:31

это работает - не могли бы вы добавить пояснение к коду, который вы изменили? особенно используя export default withApollo(ArticlesIndex);

GregH 18.02.2019 14:11

Я немного объяснил свой ответ, пожалуйста, проверьте и дайте мне знать, понятны ли они вам @GregH

Rachid Rhafour 18.02.2019 18:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
12
1 648
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы использовали JSX в componentDidMount, вместо этого вы можете сделать 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.info("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>
     );
   }
}

Проблема заключалась в том, что вы использовали JSX внутри ComponentDidMount, который не поддерживается в реакции, чтобы использовать запросы в методах жизненного цикла, вы должны обернуть компонент withApollo, и это добавит клиента в реквизит (таким образом, export default withApollo(ArticlesIndex);), затем вы можете сделать this.props.client.query в componentDidMount, а затем установить состояние.

Другие вопросы по теме