I was implementing GraphQl in React Native but I encountered a problem where while using useQuery for one exported object I did not have use the data key with the data but for the the other passed data I had to use it. Otherwise the data was undefined. Can someone please explain this working of useQuery?
I am attaching code snippet for better understanding.
const { loading, error, data } = useQuery(COUNTRY_QUERY);// Not above
const { loading2, error2, data: data2 } = useQuery(COUNTRY_CODE_QUERY); //It had to be used here
This is the query that I typed:
export const COUNTRY_QUERY = gql`
query CountryQuery {
countries {
name
}
}
`;
export const COUNTRY_CODE_QUERY = gql`
query {
country(code: "BR") {
name
capital
code
native
emoji
currency
}
}
`;
I have tried it with different parameters but it was no use.
Related
I'm working on a simple blog, I'm using Vue3 and Villus to send GraphQL queries. I build a component that shows all my posts. This works fine, in this component I send the ID in the URL for a single Post. For that, I build a blogpost_gql component. I need the ID for a GraphQL query. The ID is a part of the URL from Vue Router.
The URL looks like this:
text
The I tried to use: `
this.$route.params.id
`
This function doesn't work in setup(). The static id in variables works well to query the schema. I figured out that this has something to do with lifecycle hooks. But I don't find a solution.
This is my current code:
`
<script>
import { useQuery } from 'villus';
import ImageText from "#/components/Molecules/ImageText/ImageText";
export default {
name: "BlogEntry_GraphQL",
components: {ImageText},
setup() {
console.log('Hallo setup')
const PostById = `
query PostById ($id: String) {
postById (id: $id){
title
publishDate
author
category
imageUrl
content
id
published
slug
}
}
`;
const { data } = useQuery({
query: PostById,
variables: { id: this.$route.params.id },
});
return { data };
},
};
</script>
`
I really hope, that you can help me.
I want to get the id from the URL. After this I want to use this ID to make a query.
In Vue3, the setup lifecycle hook is a bit special: it doesn't have access to this, because the component hasn't been created yet. So this refers to nothing.
To access the current route state, you have to use the exposed vue-router composables, as explained in the documentation: vue-router composition-api:
export default {
setup() {
const route = useRoute()
const blogId = route.params.id
}
}
I am working with Vue 3 composition api and am retrieving weather data via async/await fetch and I get a 200 response and the data in the request within the Chrome Dev Tools.
In the component receiving the data and making the call I have a provide method and then I am injecting the data into another output component. The issue is in the inject component. The value for the injected variable is always null and does not update in the Vue Dev Tools so my data is never output to the screen. I went through the docs and the code is pretty much the same but I can't get it to work. Can anyone see an obvious issue?
Receiving Component
setup () {
async function getCurrentWeather () {
const response = await fetch(`${baseWeatherApiUrl}q=${userInput.value}`);
userInput.value = null;
return weatherData.value = await response.json();
}
const returnedWeatherData = reactive(weatherData);
provide('returnedWeatherData', returnedWeatherData);
return {
getCurrentWeather,
userInput,
weatherData
}
}
output component
setup () {
//Provide default of empty object in case no results exist
const weatherData = inject('returnedWeatherData');
console.log(weatherData) //No output even when making a new request to the weather api
return {
weatherData
}
}
As a separate test I tried to provide/inject hardcoded values found in the docs but still geolocation when injected remains null.
provide('geolocation', {
longitude: 90,
latitude: 135
})
const userGeolocation = inject('geolocation')
console.log(userGeolocation) // Nothing logged
return {
weatherData,
userGeolocation
}
In my case it was importing inject from "#vue/runtime-core" instead of "vue".
Of course provide was imported from "vue".
Just leaving here, maybe it's gonna save someone an hour.
The provide-ed argument should be the ref itself (not wrapped in a reactive()):
// Parent.vue
export default {
setup () {
const weatherData = ref()
// ❌
// const returnedWeatherData = reactive(weatherData);
// provide('returnedWeatherData', returnedWeatherData);
// ✅
provide('returnedWeatherData', weatherData);
}
}
And the child component's console.log() in setup() does not automatically get invoked again. You should wrap that call with watchEffect() so that it does get called upon change to the ref:
// Child.vue
import { inject, watchEffect } from 'vue'
export default {
setup () {
const weatherData = inject('returnedWeatherData')
// ❌
//console.log('new weatherData', weatherData.value)
// ✅
watchEffect(() => {
console.log('new weatherData', weatherData.value)
})
}
}
demo
Background: I'm working on building a mobile app with react-native, and am setting up AWS's AppSync for synchronizing the app with cloud data sources.
The challenge: I have a view which shows all items in a list. The list's ID is passed in as a prop to the component. I need to use that list ID to query for the items of that list. I have the query working fine if I hard-code the list ID, but I'm having a hard time figuring out how to dynamically set the list ID for the query when props update.
Here's what I have working (with a hard-coded ID of testList01) in my ListPage component:
const getListItems = id => gql`
query getListItems {
getListItems(listID: ${id}) {
reference_id,
quantity,
}
}
`;
export default graphql(getListItems('testList01'), {
options: {
fetchPolicy: 'cache-and-network',
},
props: props => ({
listItems: props.data ? props.data.getListItems : [],
data: props.data,
}),
})(withNavigationFocus(ListPage));
I would like to be able to dynamically set which list to look up the items for based on a list ID, which is being passed in from props. Specifically, I'm using react-navigation to enter the ListPage, a view where a user can see the items on a List. So here's the code that gets executed when a user clicks on a list name and gets routed to the ListPage component:
handleListSelection(list: Object) {
const { navigation, userLists } = this.props;
navigation.navigate('ListPage', {
listID: list.record_id,
listName: list.list_name,
userLists,
});
}
From my previous (pre-AppSync/GraphQL) implementation, I know that I can access the list ID in ListPage via this.props.navigation.state.params.listID. I would like to be able to use that in my AppSync query, but because the query is created outside the component, I'm unable to access the props, and so am struggling to get the ID.
Got this working using a package called react-apollo-dynamic-query which I found here. The author of that package also links directly to a simple function for doing what I'm trying to do here.
Essentially it just wraps the regular graphql call in a simple way that exposes the props so they can be passed down to the query.
My code now looks likes this (which I have below my definition of the ListPage component, in the same file):
const getListItems = props => {
const listID = props.navigation.state.params.listID;
return gql`
query getListItems {
getListItems(listID: "${listID}") { // Note the variable being wrapped in double quotes
reference_id,
quantity,
}
}
`;
};
const config = {
options: {
fetchPolicy: 'cache-and-network',
},
props: props => ({
listItems: props.data ? props.data.getListItems : [],
}),
};
const MyApolloComponent = graphqlDynamic(getListItems, config)(ListPage);
export default MyApolloComponent;
It should work like this:
const getListItems = (id) => {
return gql`
query getListItems {
getListItems(listID: ${id}) {
reference_id,
quantity,
}
}
`;
}
Call this getListItems like the below
export default graphql(getListItems(id), { //from where ever you want to send the id
options: {
fetchPolicy: '
......
I have not tested this code. Please update if this works. Although I am quite sure that it works.
I have an apollo-wrapped component that's supposed to provide my component with response data from the github graphql v4 api. I intend to use a string(SEARCH_QUERY) from another part of the app to be used in my gql query but github keeps returning undefined. I am following offical apollo docs http://dev.apollodata.com/react/queries.html#graphql-options.
I dont see what I am doing wrong.
import React, { Component } from 'react';
import { Text, FlatList } from 'react-native';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
import { SEARCH_QUERY } from './Home' // this is a string like "react"
// The data prop, which is provided by the wrapper below contains,
// a `loading` key while the query is in flight and posts when ready
const ReposList = ({ data: { loading, search }}) => <Text>SearchResults</Text>
// this doesnt work because I cant properly inject 'SEARCH_QUERY' string
const searchRepos = gql`
query searchRepos($type: searchType!, $query: String!) {
search(type: REPOSITORY, query: $query, first: 100) {
edges {
node {
... on Repository {
nameWithOwner
owner {
login
}
}
}
}
}
}
`
// The `graphql` wrapper executes a GraphQL query and makes the results
// available on the `data` prop of the wrapped component (ReposList here)
export default graphql(searchRepos, {
options: { variables: { query: SEARCH_QUERY }, notifyOnNetworkStatusChange: true }
}
)(ReposList);
This query without variables works well and returns search results as expected. straight forward, right?
const searchRepos = gql`{
search(type: REPOSITORY, query: "react", first: 100) {
edges {
node {
... on Repository {
nameWithOwner
owner {
login
}
}
}
}
}
}
`
When this is used github returns undefined.
const searchRepos = gql`
query searchRepos($type: searchType!, $query: String!) {
search(type: REPOSITORY, query: $query, first: 100) {
edges {
node {
... on Repository {
nameWithOwner
owner {
login
}
}
}
}
}
}
`
Your query is erroring out because you've defined a variable $type -- but you don't actually use it inside your query. You don't have to actually send any variables with your query -- you could define one or more in your query and then never define any inside the graphql HOC. This would be a valid request and it would be up to the server to deal with the undefined variables. However, if you define any variable inside the query itself, it has to be used inside that query, otherwise the query will be rejected.
While in development, you may find it helpful to log data.error to the console to more easily identify issues with your queries. When a query is malformed, the errors thrown by GraphQL are generally pretty descriptive.
Side note: you probably don't want to use a static values for your variables. You can calculate your variables (and any other options) from the props passed down to the component the HOC is wrapping. See this section in the docs.
const options = ({someProp}) => ({
variables: { query: someProp, type: 'REPOSITORY' },
notifyOnNetworkStatusChange: true,
})
export default graphql(searchRepos, {options})(ReposList)
I'm developing an offline-first Expo/React Native app, using GraphQL + Apollo Client + Join Monster, and storing data in a sqlite db client-side.
My schema (and the rest of the code) looks very similar to this one https://github.com/tslater/reactnative-relay-offline/blob/master/graphql/relay-schema/index.js except instead of using Relay, I am using Apollo Client as my GraphQL client.
I have a custom networkInterface that looks like:
import schema from './graphql/relay-schema'
class LocalNetworkInterface implements NetworkInterface {
constructor(schema) {
this.schema = schema
}
query(request) {
const { query, variables } = request
return graphql(
this.schema,
printAST(query),
null,
null,
variables,
)
}
getSchema() {
return this.schema
}
}
export function createLocalNetworkInterface(options) {
const { schema } = options
return new LocalNetworkInterface(schema)
}
const networkInterface = createLocalNetworkInterface({ schema })
const client = new ApolloClient({networkInterface})
and this works well for offline queries.
However, I'm unsure of how to adapt this in order to be able to make queries against a real server when the app detects it has an internet connection. The gql query I would issue against the server is slightly different that the one I issue against the local db, if that matters. Is https://github.com/apollographql/apollo-link something that would be helpful here?
I found some excellent documentation from Apollo Data that deals exactly with this issue, http://dev.apollodata.com/core/network.html#CustomNetworkInterfaceExample
I combined this with the react-native-offline package to get me an isConnected prop, which I can pass alongside my query variables, and created a new HybridNetworkInterface:
import {createNetworkInterface} from 'apollo-client'
import {createLocalNetworkInterface} from './LocalNetworkInterface'
export class HybridNetworkInterface {
constructor(opts) {
this.localInterface = createLocalNetworkInterface(opts)
this.networkInterface = createNetworkInterface(opts) // createNetworkInterface
}
query(request) {
if (request.variables && request.variables.isConnected) {
return this.networkInterface.query(request)
}
return this.localInterface.query(request)
}
use(middlewares) {
this.networkInterface.use(middlewares)
this.localInterface.use(middlewares)
return this
}
useAfter(afterwares) {
this.networkInterface.useAfter(afterwares)
this.localInterface.useAfter(afterwares)
return this
}
}
export function createHybridNetworkInterface(opts) {
return new HybridNetworkInterface(opts)
}