Lets assume I have the following GraphQL query in React-Apollo
const CurrentUserForLayout = gql`
query CurrentUserForLayout($avatarID: Int!) {
currentUser {
avatar_url(avatarID: $avatarID)
}
}
`;
const ProfileWithData = graphql(CurrentUserForLayout, {
options: { variables: { avatarID: 1 } },
})(Profile);
Now if I want to let my React component Profile
change the avatarID,
how would I do that?
I am new to React and GraphQl and I do not really understand the connection here:
graphql(CurrentUserForLayout, {
options: { variables: { avatarID: 1 } },
})(Profile);
Do I really need another parent component around ProfileWithData
to pass another avatarID
to the query? But what if the ID is manipulated by the Profile component, how do I let the Parent component know about that?
Your
ProfileWithData
component does a good job of rendering the avatar of a certain user. It's not the responsiblity of this component to manage changes of the currently displayed avatar component.One way is to add a new prop
avatarId
that gets passed down from the parent component. Then you would need to write this:If you are familiar with
react-router
, another approach would be to use the route parameters to determine the avatar id. You would need to adjust the call ofgraphql
like this:To read more about the usage of query variables like this, you can check the React Track of Learn Apollo.
Before Apollo Client 2.1
Before Apollo Client 2.1, when you had to use Higher-Order Components (HOCs), there were two solutions which were pointed out correctly by henk in the other answer. I try to summarize them briefly:
Since the HOC has only access to the props, you need to introduce the changing variable in your parent component. For instance, the parent component could have local state management in place for the changing variable with React's
setState()
method. Once the variable changes in the local state, it can be passed down to your other component which is enhanced by the HOC. The HOC has access to the props and can execute the query with a changed variable. Hint: If you don't want to introduce another component in between to change the local state, recompose'swithState
HOC might be a great choice.The second way, but maybe less elegant way, because it shifts your code from declarative to imperative, would be to use the
withApollo()
HOC which gives you access to the Apollo Client instance as prop. Having this instance in your React component, you can callclient.query({ query: ..., variables: ... })
in one of your component's class methods (e.g.onChange
handler) once your variable changes.Since Apollo Client 2.1
Since Apollo Client 2.1 you can use the new Query (and Mutation) component. The HOC still exists though, but isn't advertised by the documentation anymore. However, the new Query (and Mutation) component is used within your component. It uses React's render props pattern.
By shifting this control flow inside of the component rather than having it only co-located with a HOC, you can pass the changing prop as variable to your Query (and Mutation) component.
If you want to learn Apollo Client in React, checkout this extensive tutorial. Note: Code Snippets are taken from the Apollo Client 2.1 release blog post.
So far, I know two possible approaches to this.
The first one is already stated in the question. The variables are at the same time the props of the
ProfileWithData
. So you need to find a way to change the props and rerender the component. This is usually achieved with a parent component. So usually you do not change the variables inside ofProfileWithData
. This component should be used only for display purposes. However, this does not say that it can't be done. You can pass the methods of your parent component to the child in order to manipulate the state of the parent. This will rerender both components and render theProfileWithData
with new props/variables.The second approach is to query from the inside of the
ProfileWithData
component. You can then manipulate the variables from the inside of the component with the state. A method to do this can be found here