可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a queries file that looks like this:
import {gql} from 'react-apollo';
const queries = {
getApps: gql`
{
apps {
id
name
}
}
`,
getSubjects: gql`
{
subjects {
id
name
}
}
`
};
export default queries;
I then import this file to my React component:
import React, {Component} from 'react'
import queries from './queries'
class Test extends Component {
...
}
export default graphql(queries.getSubjects)(graphql(queries.getApps)(Test));
This will only get data for one of the queries (getApps) and not both. If I do one at a time so that it looks like this:
export default graphql(queries.getSubjects)(Test);
then it works but I don't have my other query. Yes, I have tested both separately and they work. How do I get it so that both queries show up in my props.data?
回答1:
My preferred way is to use the compose
functionality of the apollo client (docu).
EDIT:
If you have more than one query you should name them.
So in your case, it could look like this:
import React, {Component} from 'react'
import queries from './queries'
import { graphql, compose } from 'react-apollo';
class Test extends Component {
...
render() {
...
console.log(this.props.subjectsQuery, this.props.appsQuery); // should show both
...
}
}
export default compose(
graphql(queries.getSubjects, {
name: "subjectsQuery"
}),
graphql(queries.getApps, {
name: "appsQuery"
}),
)(Test);
回答2:
If you don't want to reuse any of those queries independently, why not make a single request by combining both queries in one i.e:
const combinedQueries = gql`
{
apps {
id
name
}
subjects {
id
name
}
}
`
and then you can use it in your component
import React, {Component} from 'react'
import combinedQueries from './combinedQueries'
class Test extends Component {
...
render() {
...
if(!this.props.combinedQueries.loading) {
console.log(this.props.combinedQueries.apps);
console.log(this.props.combinedQueries.subjects);
}
...
}
}
export default graphql(combinedQueries, {name: 'combinedQueries'})(Test);
回答3:
For Apollo 2.x: you can use react-adopt
to compose the Queries and Mutations into a single level. (That lib will compose any components with render props, e.g. the React Context API.)
https://github.com/pedronauck/react-adopt
回答4:
IMHO, one of the most neat solutions is described in the Apollo Client React implementation.
The basic idea is to wrap your queries into nested Query components. Using closure functions as component children makes it handy to delegate the results of one query down into another query and so on.
const QueryOne = gql`
query One {
one
}
`;
const QueryTwo = gql`
query Two {
two
}
`;
const NumbersWithData = () => (
<Query query={QueryOne}>
{({ loading: loadingOne, data: { one } }) => (
<Query query={QueryTwo}>
{({ loading: loadingTwo, data: { two }}) => {
if (loadingOne || loadingTwo) return <span>loading...</span>
return <h3>{one} is less than {two}</h3>
}}
</Query>
)}
</Query>
);
回答5:
I'm using react-adopt to make this. It's really simple and keep our code clean.
Simple example:
import { adopt } from 'react-adopt';
...
render() {
const Composed = adopt({
first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>,
second: ({ render }) => <Query query={SECOND_QUERY}>{ render }</Query>
});
return (
<Composed>
({ first, second }) => {
console.log('first', first)
console.log('second', second)
// validations (loading, error)
return (
<div>Your JSX</div>
)
}
</Composed>
)
}
...
There are a lot of examples using
const Composed = adopt({
first: <Query query={FIRST_QUERY} />,
second: <Query query={SECOND_QUERY} />
});
Be careful with <Query>
component, It needs a children, otherwise, it will have the following error:
Warning: Failed prop type: The prop children is marked as required in Query, but its value is undefined.
To avoid the previous warning, I have found a possible solution:
first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>
Hope it helps you!
回答6:
Another way around this is to use the props
option.
export default compose(
graphql(QUERY_2, {
props: ({ data }) => ({ ...data }),
}),
graphql(QUERY_1, {
props: ({ data }) => ({ ...data, myCustomAttribute: data.foo }),
}),
)(Component);
I've found that this approach is a bit nicer for my use case.
Here is a link to the docs: https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-config-props
回答7:
A query and mutation using react-apollo's compose
Things that I've concluded:
- Compose runs it's queries from the bottom up.
- Queries are run automatically, you don't have to call them, but Mutations you do.
- It's apparent that the Apollo team wants everyone to use the Query component rather than compose. Therefore, I think it would be wise to use they Query Component as they suggest because they might deprecate compose later.
Here's the code if you still want to use compose:
import {gql} from 'graphql-tag'
import {graphql, compose} from 'react-apollo'
import React, {Component} from 'react'
const appQuery = gql`
{
apps {
id
name
}
}
`
const subjectMutation = gql`
mutation someName($name: String) {
changeSubjects(name: $name) {
subject {
name
}
}
}
`
};
class Test extends Component {
...
const MutationResponse = this.props.mutate({
variables: {
name: "some name"
}
})
const QueryResponse = this.props.data.appQuery
...
}
export default compose(
graphql(appQuery),
graphql(subjectMutation)
)(Test));