How to capture the response of a query in GraphQL Relay - reactjs

I am new to relay, I have a query that delivers a response, which I can see in the network tab of the inspector, but what I dont understand is how to grab that response for use in my component. Could someone please explain that?
My query is
const query = graphql`
query AdvisorProfileQuery($id: ID!) {
node(id: $id) {
...on Advisor {
name
postalCode
products
referralCode
status
updatedAt
}
}
}`;
and runs through the renderer
const QueryRenderer = LoadingQueryRenderer(AdvisorProfile, query);
export default ({ i18n }) => {
return (
<>
<QueryRenderer
params={{ id: id }}
/>
</>
);
};
but what is the variable name that holds that data that is returned to the component? I want to pass that data as a prop to another component.
This is how the response looks

You can follow the example from official docs
import React from 'react';
import { QueryRenderer, graphql } from 'react-relay';
const Example = (props) => {
return (
<QueryRenderer
environment={environment}
query={graphql`
query ExampleQuery($pageID: ID!) {
page(id: $pageID) {
name
}
}
`}
variables={{
pageID: '110798995619330',
}}
render={({ props }) => {
if (props) {
return <ChildComponent page={page.name} />;
}
return <div>Loading</div>;
}}
/>
);
}
you can consume the data inside the QueryRenderer render like usual props

Related

Apollo GraphQL query inside of react custom hook

I'm trying to list all the characters from Rick & Morty API. I wrote the following hook to use in my Component that is going to render the result. When I hardcoded values eg: (page: 1 , filter: { name : "Rick"}) The query runs just fine.If I try to use variables it returns an error 400 bad request (I'm assuming this means my $page / $filter values are invalid and I tried to check the values within them + their types everything seemed fine)I looked at the documentation at Apollo | Queries - Client (React) and made sure that I was using the proper syntax to inject variables into the query. The query is from the official Rick & Morty API docs API Docs. Any guidance/direction is much appreciated.
useCharecterList Hook
Params: page: Number | filter: String
import { useQuery, gql } from '#apollo/client';
const CHARECTERS_LIST = gql`
query ($page: Number!, $filter: String!){
characters
(page: $page , filter: { name : $filter}) {
info {
next
prev
}
results {
id
name
image
}
}
}
`;
export default function useCharecterList({page, filter}){
return useQuery(CHARECTERS_LIST, {
variables: {page, filter}
});
}
Component Rendering the results:
import useCharecterList from '../hooks/useCharecterList'
import { Fragment } from 'react';
import InputComponent from './InputComponent';
function CharectersList() {
const { loading, error, data } = useCharecterList({page: 1, filter: "Rick"});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
const options = data.characters.results.map(({name}) =>{
return name;
})
return(
<Fragment>
<InputComponent options={options}></InputComponent>
{
data.characters.results.map(({ id, name, image }) => (
<div key={id}>
<img src={image} alt={`${name} from the popular sitcom Rick & Morty`}/>
<p>{name}</p>
</div>
))
}
</Fragment>
)
}
export default CharectersList
I figured it out... Like an Idiot I assumed the query types are just your normal JS types. After some digging I got it to work as follows.
import { useQuery, gql } from '#apollo/client';
const CHARECTERS_LIST = gql`
query CharectersList($page: Int!, $filter: FilterCharacter!){
characters
(page: $page, filter: $filter) {
info {
next
prev
}
results {
id
name
image
}
}
}
`;
export default function useCharecterList(options){
return useQuery(CHARECTERS_LIST, options);
}
import useCharecterList from '../hooks/useCharecterList'
import { Fragment } from 'react';
import InputComponent from './InputComponent';
function CharectersList() {
const { loading, error, data } = useCharecterList({variables: {page: 1, filter: { name: "Summer" }}});
if (loading) return <p>Loading...</p>;
if (error) {
console.log(error);
return <p>Error :(</p>}
const options = data.characters.results.map(({name}) =>{
return name;
})
return(
<Fragment>
<InputComponent options={options}></InputComponent>
{
data.characters.results.map(({ id, name, image }) => (
<div key={id}>
<img src={image} alt={`${name} from the popular sitcom Rick & Morty`}/>
<p>{name}</p>
</div>
))
}
</Fragment>
)
}
export default CharectersList

How to pass data queried in one component to another component to use as a query variable?

I'm stuck trying to pass a value queried with Apollo Client in one route component to another route component to use as a variable in a query. The exact error is: "Uncaught TypeError: Cannot read property 'name' of undefined".
There are three components:
App, the root component with the router.
ComponentA, that queries a group of data by id and name to show a list of Cards for each item. Every item has a link to a to ComponentB.
Component B, which has to query more data using the name referenced by ComponentA as a variable to show more data from that item.
App.tsx
export const App: React.FunctionComponent = () => {
return (
<BrowserRouter>
<>
<Main>
<Switch>
<Route exact path="/" component={ComponentA} />
<Route path="/:name" component={ComponentB} />
</Switch>
</Main>
</>
</BrowserRouter>
);
};
ComponentA.tsx
const GET_DATAS = gql`
query GetDatas {
getDatas {
_id
name
}
}
`;
interface Data {
_id: string;
name: string;
}
export const Home: React.FunctionComponent = () => {
const { data } = useQuery(GET_DATAS);
return (
<>
<div>
{data.getDatas.map((data: Data) => (
<Link to={`/${data.name}`} key={data._id}>
<Card name={data.name} />
</Link>
))}
</div>
</>
);
};
ComponentB.tsx
const GET_DATA = gql`
query GetData($name: String!) {
getData(name: $name) {
_id
name
year
color
}
}
`;
interface Props {
name: string;
}
export const DataDetails: React.FunctionComponent<Props> = (props: Props) => {
const { data } = useQuery(GET_DATA, {
variables: { name },
});
return (
<>
<div>
<H1>{data.getData.name}</H1>
<p>{data.getData.year}</p>
<p>{data.getData.color}</p>
</div>
</>
);
};
The queries work well as I tested them in Playground, and I tried using local state and passing the props with Link with no results, but I still can't figure out how to pass the value to use in the query of ComponentB.
Thanks in advance!
Fixed 🎉 I finally opted for just taking the URL, cleaning it a bit, and using it as a variable for the query, and also adding the loading and error states:
export const DataDetails: React.FunctionComponent = () => {
const dirtyPath = location.pathname;
const cleanPath = dirtyPath.replace(/%20/g, ' ').replace(/\//g, '');
const { data, loading, error } = useQuery(GET_DATA, {
variables: { name: cleanPath },
});
return (
...
);
};
Another solution, available when using React Router, would be:
export const DataDetails: React.FunctionComponent = (props) => {
const { data, loading, error } = useQuery(GET_DATA, {
variables: { name: props.match.params.name },
});
return (
...
);
};

How can I use React component as an enhancer?

I'm a newbie and React and I've got the following piece of code:
class MyCoolComponent extends React.Component {
render() {
return (
<QueryRenderer
environment={environment}
query={graphql`
query UserQuery {
viewer {
id
}
}
`}
variables={{}}
render={({error, props}) => {
if (error) {
return <div>Error!</div>;
}
if (!props) {
return <div>Loading...</div>;
}
return <div>User ID: {props.viewer.id}</div>;
}}
/>
);
}
}
I want to use this React component as an enhancer to a different React Component to pass the data (props.viewer.id) using compose(addDataEnhancer, ...) to the other High Order Component (such that it'll be able to use props.viewer.id). How can I do it?
The context: the idea is to use this MyCoolComponent as a replacement for the data source function here:
export default compose(
// data source
graphql(gql`query MyQuery1 { ... }`),
)(MyHOCComponent);
function MyHOCComponent({ data }) {
console.log(data);
}
I think this should work. compose will call first hoc with base component, than return value (wrapped component) is passed to next hoc (next compose argument), etc...
Base component (and every HOC listed after this HOC) will have prop viewerId
// withViewerId.js
import React from 'react'
import { QueryRenderer, graphql } from 'react-relay'
import environment from 'environment'
export default (BaseComponent) => (restProps) => (
<QueryRenderer
environment={environment}
query={graphql`
query UserQuery {
viewer {
id
}
}
`}
variables={{}}
render={({error, props}) => {
if (error) {
return <div>Error!</div>;
}
if (!props) {
return <div>Loading...</div>;
}
return <BaseComponent {...restProps} viewerId={props.viewer.id} />;
}}
/>
)
usage:
import withViewerId from 'withViewerId'
export default compose(withViewerId)(BaseComponent)

Gatsby GraphQL error: Variable "$slug" is never used in operation "BlogPostQuery"

I am unable to pull in the data of my Ghost blog using Gatsby. I am using Ghost as my back end and I am using a package to get the Ghost blog as a source. The problem is just getting the individual posts on the page. Here is blog-post.js:
import React from "react";
export default ({ data }) => {
// const post = data.allGhostPost.edges;
return (
<div>
{/* <h1>{post.title}</h1> */}
{/* <div dangerouslySetInnerHTML={{ __html: post.html }} /> */}
</div>
);
};
export const query = graphql`
query BlogPostQuery($slug: String!) {
allGhostPost {
edges {
node {
id
slug
title
html
published_at
}
}
}
}
`;
Here is my gatsby node file:
exports.createPages = ({ graphql, boundActionCreators}) => {
const {createPage} = boundActionCreators
return new Promise((resolve, reject) => {
const blogPostTemplate = path.resolve(`src/templates/blog-post.js`)
resolve(
graphql(
`
{
allGhostPost(sort: { order: DESC, fields: [published_at] }) {
edges {
node {
id
slug
title
html
published_at
}
}
}
}
`
)
.then(result => {
result.data.allGhostPost.edges.forEach(edge => {
createPage({
path: edge.node.slug,
component: blogPostTemplate,
context: {
slug: edge.node.slug
}
})
})
return;
})
)
})
}
I figured out my problem and it was a problem with my Queries. For anyone working with the Ghost API. This is the answer you will need:
query BlogPostQuery($slug: String!) {
allGhostPost(filter: {slug: {eq: $slug}}) {
edges {
node {
id
slug
title
html
published_at
}
}
}
}
Let me explain my answer.
The issue was that my GraphQL query was not working because the $slug field was not being used within the query. It was just being passed in. That being said, I had to learn a bit of GraphQL to get to my final conclusion.
Using the GraphiQL I was able to find that the allGhostPost had a filter method. Using that I was able to pull in the right result.

Access a state value to passing it as parameter of a query

I'm having a little problem. Being a beginner in "react apollo ...", I want to pass the value of my state "selectCarcolor" as parameter of my query.This must be done when I select a color from the drop-down list.I read a lot of things in the documentation but I do not know where to start.
You can see all of my code here: Github link description here
onChangeCarColor(e){
//const selectCarcolor = this.state.selectCarcolor
this.setState({ selectCarcolor:e.target.value})
console.log("color " + this.state.selectCarcolor);
}
const Cquery = `gql query getAllUsers($color: String!) {
getAllUsers(color: $color) {
_id
name
cars {
color
}
}
}`;
const datafetch = graphql(Cquery, {
options: props=> ({
variables: { color: **Here I want to pass the select value**},
})
});
Hoping for a little help from you.
Thank you guys!
react version :16.2.0
react-apollo version : 2.0.1
You can wrap your component with withApollo function from react-apollo package which injects the ApolloClient into your component (available as this.props.client). You can send a query using it. Check official docs and this tutorial for more details and explanations.
Example:
import React, { Component } from 'react'
import { withApollo } from 'react-apollo'
import gql from 'graphql-tag'
import Link from './Link'
class Search extends Component {
state = {
links: [],
filter: ''
}
render() {
return (
<div>
<div>
Search
<input
type='text'
onChange={(e) => this.setState({ filter: e.target.value })}
/>
<button
onClick={() => this._executeSearch()}
>
OK
</button>
</div>
{this.state.links.map((link, index) => <Link key={link.id} link={link} index={index}/>)}
</div>
)
}
_executeSearch = async () => {
const { filter } = this.state
const result = await this.props.client.query({
query: FEED_SEARCH_QUERY,
variables: { filter },
})
const links = result.data.feed.links
this.setState({ links })
}
}
const FEED_SEARCH_QUERY = gql`
query FeedSearchQuery($filter: String!) {
feed(filter: $filter) {
links {
id
url
description
createdAt
postedBy {
id
name
}
votes {
id
user {
id
}
}
}
}
}
`
export default withApollo(Search)
In your datafetch() function you are setting option variables in a function on props, but you are setting your color selected to your state.
Can you just do
options: {
variables: { color: this.state.selectCarcolor, }
}
instead of what you are doing?

Resources