私は単純なアプリケーションにもっと多くの機能をロードしようとしています。 SequelizeとGraphQLを使ってMySQLからデータを取得します。私は私のアプリケーションの足場として、リレースターターキットを使用しています。リレースローエラー:未定義のプロパティ 'reduce'を読み取ることができません
database.js
import Sequelize from 'sequelize';
import _ from 'lodash';
import Faker from 'faker';
const Conn = new Sequelize('relay', 'root', '', {
host: 'localhost',
dialect: 'mysql'
});
const Person = Conn.define('person', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
validate: {
isEmail: true
}
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
}
});
const Post = Conn.define('post', {
title: {
type: Sequelize.STRING,
allowNull: false
},
content: {
type: Sequelize.STRING,
allowNull: false
}
});
// Relationships
Person.hasMany(Post);
Post.belongsTo(Person);
Conn.sync({ force: true }).then(() => {
_.times(10,() => {
return Person.create({
firstName: Faker.name.firstName(),
lastName: Faker.name.lastName(),
email: Faker.internet.email(),
createdAt: Date.now(),
updatedAt: Date.now()
}).then(person => {
return person.createPost({
title: `Sample title by ${person.firstName}`,
content: 'This is a sample article'
});
});
})
});
// Model types
class User { }
// Mock data
var viewer = new User();
viewer.id = '1';
module.exports = {
// Export methods that your schema can use to interact with your database
getUser: (id) => id === viewer.id ? viewer : null,
getViewer:() => viewer,
Conn
};
schema.js
import {
GraphQLBoolean,
GraphQLFloat,
GraphQLID,
GraphQLInt,
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
} from 'graphql';
import {
connectionArgs,
connectionDefinitions,
connectionFromArray,
connectionFromPromisedArraySlice,
connectionFromPromisedArray,
fromGlobalId,
globalIdField,
mutationWithClientMutationId,
nodeDefinitions,
} from 'graphql-relay';
import {
// Import methods that your schema can use to interact with your database
getUser,
getViewer,
Conn
} from './database';
/**
* We get the node interface and field from the Relay library.
*
* The first method defines the way we resolve an ID to its object.
* The second defines the way we resolve an object to its GraphQL type.
*/
var {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
var {type, id} = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof User) {
return userType;
} else {
return null;
}
}
);
/**
* Define your own types here
*/
const Person = new GraphQLObjectType({
name: "Person",
description: "This represents a person",
fields:() => {
return {
id: {
type: GraphQLString,
resolve(person) {
return person.id
}
},
firstName: {
type: GraphQLString,
resolve(person) {
return person.firstName
}
},
lastName: {
type: GraphQLString,
resolve(person) {
return person.lastName
}
},
email: {
type: GraphQLString,
resolve(person) {
return person.email
}
},
posts: {
type: new GraphQLList(Post),
resolve(person) {
return person.getPosts();
}
}
}
}
});
const Post = new GraphQLObjectType({
name: "Post",
description: "This is a post",
fields:() => {
return {
id: {
type: GraphQLString,
resolve(person) {
return person.id;
}
},
title: {
type: GraphQLString,
resolve(post) {
return post.title;
}
},
content: {
type: GraphQLString,
resolve(post) {
return post.content;
}
},
person: {
type: Person,
resolve(post) {
return post.getPerson();
}
}
}
}
})
var userType = new GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
fields:() => ({
id: globalIdField('User'),
people: {
type: personConnection,
description: 'A collection of persons',
args: connectionArgs,
resolve(_, args, info) {
console.log("==== INFO ====");
console.log(info);
let gas = {};
gas.first= args.first;
gas.after = args.after;
gas.find = args.find;
delete args.first;
delete args.after;
delete args.find;
return connectionFromPromisedArray(Conn.models.person.findAll({ where: args }), gas);
}
},
})
});
var {connectionType: personConnection} =
connectionDefinitions({ name: 'Person', nodeType: Person });
/**
* This is the type that will be the root of our query,
* and the entry point into our schema.
*/
var queryType = new GraphQLObjectType({
name: 'Query',
description: "This is a root query",
fields:() => ({
node: nodeField,
// Add your own root fields here
viewer: {
type: userType,
resolve:() => getViewer(),
}
}),
});
/**
* This is the type that will be the root of our mutations,
* and the entry point into performing writes in our schema.
*/
var mutationType = new GraphQLObjectType({
name: 'Mutation',
fields:() => ({
// Add your own mutations here
})
});
/**
* Finally, we construct our schema (whose starting query type is the query
* type we defined above) and export it.
*/
export var Schema = new GraphQLSchema({
query: queryType,
types: [queryType, userType, Person, Post]
// Uncomment the following after adding some mutation fields:
// mutation: mutationType
});
App.js
import React from 'react';
import Relay from 'react-relay';
import AnimateOnChange from 'react-animate-on-change';
class Detail extends React.Component {
constructor(props) {
super(props);
this.state = { person: [] };
}
componentWillMount() {
this.setState({ person: this.props.person });
}
render() {
return (
<div>
<h2>Selected User's Detail</h2>
<div className="form-group">
<label>User ID:</label>
<p className="form-control">
<AnimateOnChange
baseClassName="animated"
animationClassName="fadeIn"
animate={true}>{this.props.person.id}</AnimateOnChange>
</p>
</div>
<div className="form-group">
<label>First Name</label>
<p className="form-control">
<AnimateOnChange
baseClassName="animated"
animationClassName="fadeIn"
animate={true}>{this.props.person.firstName}</AnimateOnChange>
</p>
</div>
<div className="form-group">
<label>Last Name</label>
<p className="form-control">
<AnimateOnChange
baseClassName="animated"
animationClassName="fadeIn"
animate={true}>{this.props.person.lastName}</AnimateOnChange>
</p>
</div>
<h2>Selected User's Posts</h2>
<table className="table table-hovered">
<thead>
<tr>
<th>No</th>
<th>Post ID</th>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
{this.props.person.posts.map((post, key) =>
<tr key={post.id} className="animated fadeIn">
<td>{key + 1}.</td>
<td>{post.id} {post[key]}</td>
<td>{post.title}</td>
<td>{post.content}</td>
</tr>
) }
</tbody>
</table>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { index: 0 }
}
_handleClick(key) {
if (this.state.index !== key) {
this.setState({ index: key })
}
}
_loadMore(){
console.log(this.props.viewer.people);
this.props.relay.setVariables({
first: this.props.relay.variables.first,
after: this.props.viewer.people.pageInfo.endCursor
});
}
render() {
console.log(this.props.viewer.people);
return (
<div className="container">
<h2>Users List</h2>
<button onClick={this._loadMore.bind(this)}>Load more</button>
<ul className="list-group">
{this.props.viewer.people.edges.map((p, key) =>
<li className={key !== this.state.index ? "list-group-item" : "list-group-item active"} onClick={this._handleClick.bind(this, key) } key={p.node.id}>{p.node.firstName} {p.node.lastName} (ID: {p.node.id}) </li>
) }
</ul>
<Detail person={this.props.viewer.people.edges[this.state.index].node}/>
</div>
)
}
}
export default Relay.createContainer(App, {
fragments: {
viewer:() => Relay.QL`
fragment on User {
people(first: $first, after: $after){
edges{
node{
id,
firstName,
lastName,
posts{
id,
title,
content
}
}
}
pageInfo{
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
`
},
initialVariables: {
first: 3,
after: null
}
});
AppHomeRoute.js
import Relay from 'react-relay';
export default class extends Relay.Route {
static queries = {
viewer: (Component) => Relay.QL`
query {
viewer {
${Component.getFragment('viewer')}
}
}
`,
};
static routeName = 'AppHomeRoute';
}
このアプリケーションは単純です。ボタンをクリックすると、「もっと負荷をかける」機能がトリガーされます。 App.jsでその機能を見ることができます。関数が実行されるたびに、返されるのは:
Cannot read property 'reduce' of undefined
です。
私は、質問が正しいことを確認しようとしました。私はGraphiQLを使用してクエリを作成しようとしたときに「興味深い」ものを見つけました。
(サーバーへの要求を行う際に、アプリケーションの方法と同じ)私はフラグメントを使用する場合:
query App_ViewerRelayQL($id_0: ID!) {
node(id: $id_0) {
id
...F0
}
}
fragment F0 on User {
_people35G0DJ: people(after: "YXJyYXljb25uZWN0aW9uOjI=", first: 2) {
edges {
node {
id
firstName
lastName
posts {
id
title
content
}
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
}
}
id
}
結果:
{
"errors": [
{
"message": "Cannot read property 'reduce' of undefined"
}
]
}
私はフラグメントを使用していない場合(生のクエリ):
query {
viewer {
id
people(after:"YXJyYXljb25uZWN0aW9uOjE=",first:2) {
edges {
node {
id
firstName
lastName
posts {
id
title
content
}
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
}
}
id
}
}
結果:
{
"data": {
"viewer": {
"id": "VXNlcjox",
"people": {
"edges": [
{
"node": {
"id": "3",
"firstName": "Filomena",
"lastName": "Ebert",
"posts": [
{
"id": "3",
"title": "Sample title by Filomena",
"content": "This is a sample article"
}
]
},
"cursor": "YXJyYXljb25uZWN0aW9uOjI="
},
{
"node": {
"id": "4",
"firstName": "Alessandra",
"lastName": "Muller",
"posts": [
{
"id": "4",
"title": "Sample title by Alessandra",
"content": "This is a sample article"
}
]
},
"cursor": "YXJyYXljb25uZWN0aW9uOjM="
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false
}
}
}
}
}
が問題であることを仮定は、クエリであるが、私はよく分かりません。私は今、少し不満を抱いています。どんな助けもありがとう。
ありがとうございました。