React with GraphQL: TypeError: parse is not a function
React with GraphQL: TypeError: parse is not a function
我目前正在尝试用对 graphql 端点的调用来替换我的 restful 调用以从服务器检索我的所有 articles
。我用 GraphiQL
测试了以下查询,它 returns 预期数据。我还使用 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
中,我设置了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...
仍然没有请求被发送到服务器。
编辑 2:我现在已经尝试了列出的每个解决方法 here 并且在尝试了更改 webpack 配置的建议之后,页面不会像以前一样出错,但是仍然没有请求发送到服务器Loading...
永远留在页面上。我的 componentDidMount
函数中的断点被击中,但似乎什么也没发生。
编辑 3:如果我用以下 restful 调用替换 graphql 调用以获取数据,一切都会正常运行,但该项目的目的是探索与 graphql 的反应。 restful 正常运行并且我正在尝试替换的调用如下:
fetch('https://localhost:44360/api/Articles/')
.then(response => response.json())
.then(data => {
this.setState({ articles: data, loading: false });
});
您在 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);
),然后您可以在 componentDidMount
中执行 this.props.client.query
然后您可以设置状态。
我目前正在尝试用对 graphql 端点的调用来替换我的 restful 调用以从服务器检索我的所有 articles
。我用 GraphiQL
测试了以下查询,它 returns 预期数据。我还使用 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
中,我设置了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...
仍然没有请求被发送到服务器。
编辑 2:我现在已经尝试了列出的每个解决方法 here 并且在尝试了更改 webpack 配置的建议之后,页面不会像以前一样出错,但是仍然没有请求发送到服务器Loading...
永远留在页面上。我的 componentDidMount
函数中的断点被击中,但似乎什么也没发生。
编辑 3:如果我用以下 restful 调用替换 graphql 调用以获取数据,一切都会正常运行,但该项目的目的是探索与 graphql 的反应。 restful 正常运行并且我正在尝试替换的调用如下:
fetch('https://localhost:44360/api/Articles/')
.then(response => response.json())
.then(data => {
this.setState({ articles: data, loading: false });
});
您在 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);
),然后您可以在 componentDidMount
中执行 this.props.client.query
然后您可以设置状态。