В настоящее время я пытаюсь заменить свой спокойный вызов для получения всех моих 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 });
});
Это проблема с версией Graphql, не могли бы вы поделиться, какую версию вы используете? вам может потребоваться понизить или обновить его.
@RachidRhafour Первоначально я использовал версию graphql 14.1.1 и попытался перейти на версию 0.12.3, чтобы решить проблему, которая привела к поведению, указанному в разделе «ИЗМЕНИТЬ» моего сообщения.
Я не уверен, какая версия может работать, но я использую Graphql v14.0.2 с «graphql-tag»: версия npm «2.10.0» 5.6.0
изменены на пакеты, которые вы упомянули, и все еще получаю ту же ошибку TypeError: parse is not a function мое использование такое же, как ваше? Я все еще не получаю никаких запросов, когда-либо отправленных на сервер, и эта ошибка возникает при переходе на страницу.
можете ли вы иметь этот пример в песочнице кода и поделиться им со мной, чтобы я мог посмотреть?
простой проект, в который он включен, находится по адресу bitbucket.org/greghofman/реакттофакты/src/развитие, он включает в себя базовую часть .net, которая включает в себя graphql. Приложение React находится в ReactToFacts.Client.
Думаю, я нашел почему, дайте мне второй, плз.
проверьте мой ответ, пожалуйста, дайте мне знать, если он работает для вас :)
можешь проверить мой ответ?
это работает - не могли бы вы добавить пояснение к коду, который вы изменили? особенно используя export default withApollo(ArticlesIndex);
Я немного объяснил свой ответ, пожалуйста, проверьте и дайте мне знать, понятны ли они вам @GregH





Вы использовали 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, а затем установить состояние.
У вас есть схема для проверки запроса, который вы написали, я сомневаюсь, что это правильный способ написать его, но если у вас есть схема, двойная проверка.