react-query tips and tricks i've found usefull while working with github's graphql api
using select to insert a new value into the response
import React from 'react'
import { useQuery } from 'react-query' ;
import { GraphQLClient } from 'graphql-request' ;
import { gql } from 'graphql-tag' ;
interface TestProps {
token :string
}
interface User {
user :Root
}
export interface Root {
login : string ;
id : string ;
isFollowingViewer : boolean ;
viewerIsFollowing : boolean ;
bio : string ;
avatarUrl : string ;
isViewer : boolean ;
url : string ;
}
export const Test : React . FC < TestProps > = ( { token} ) => {
const username = 'tigawanna'
const key = [ 'user' ]
const USER = gql `
query getMiniUser($name: String!) {
user(login: $name) {
login
id
isFollowingViewer
viewerIsFollowing
bio
avatarUrl
isViewer
url
}
}
` ;
const endpoint = "https://api.github.com/graphql" ;
const headers = {
headers : {
Authorization : `Bearer ${ token } ` ,
"Content-Type" : "application/json" ,
} ,
} ;
const graphQLClient = new GraphQLClient ( endpoint , headers ) ;
const fetchData = async ( ) => await graphQLClient . request ( USER , { name :"tigawanna" } ) ;
const query = useQuery ( key , fetchData ,
{
enabled : username . length > 3 ,
select : ( data :User ) => {
let newdata
if ( data . user . isViewer ) {
newdata = { ...data . user , OP :true }
return { user :newdata }
}
return data
}
}
)
console . log ( "test query === " , query . data )
return (
< div className = 'w-full h-full ' >
HELLO
< / div>
) ; }
using select to filter the response array
import React from 'react'
import { useQuery } from 'react-query' ;
import { GraphQLClient } from 'graphql-request' ;
import { gql } from 'graphql-tag' ;
interface TestProps {
token :string
}
interface User {
user :Root
}
export interface Followers {
edges : Edge [ ] ;
}
export interface Edge {
node : Node ;
}
export interface Node {
login : string ;
avatarUrl : string ;
id : string ;
}
export interface Root {
login : string ;
id : string ;
isFollowingViewer : boolean ;
viewerIsFollowing : boolean ;
bio : string ;
avatarUrl : string ;
isViewer : boolean ;
url : string ;
followers : Followers ;
}
export const Test : React . FC < TestProps > = ( { token} ) => {
const username = 'tigawanna'
const key = [ 'user' ]
const USER = gql `
query getMiniUser($name: String!) {
user(login: $name) {
login
id
isFollowingViewer
viewerIsFollowing
bio
avatarUrl
isViewer
url
followers(first:10) {
edges {
node {
login
avatarUrl
id
}
}
}
}
}
` ;
const endpoint = "https://api.github.com/graphql" ;
const headers = {
headers : {
Authorization : `Bearer ${ token } ` ,
"Content-Type" : "application/json" ,
} ,
} ;
const graphQLClient = new GraphQLClient ( endpoint , headers ) ;
const fetchData = async ( ) => await graphQLClient . request ( USER , { name :"tigawanna" } ) ;
const keyword = "a"
const query = useQuery ( key , fetchData ,
{
enabled : username . length > 3 ,
select : ( data :User ) => {
let newdata
if ( keyword ) {
const followers = data . user . followers . edges . filter ( ( item ) => {
return item . node . login . includes ( keyword )
} )
newdata = { ...data . user , followers}
return { user :newdata }
}
return data
}
}
)
console . log ( "test query === " , query . data )
return (
< div className = 'w-full h-full ' >
HELLO
< / div>
) ; }
onError and onSuccess side effects
import React from 'react'
import { useQuery } from 'react-query' ;
import { GraphQLClient } from 'graphql-request' ;
import { gql } from 'graphql-tag' ;
interface TestProps {
token :string
}
interface User {
user :Root
}
export interface Followers {
edges : Edge [ ] ;
}
export interface Edge {
node : Node ;
}
export interface Node {
login : string ;
avatarUrl : string ;
id : string ;
}
export interface Root {
login : string ;
id : string ;
isFollowingViewer : boolean ;
viewerIsFollowing : boolean ;
bio : string ;
avatarUrl : string ;
isViewer : boolean ;
url : string ;
followers : Followers ;
}
export const Test : React . FC < TestProps > = ( { token} ) => {
const username = 'tigawanna'
const key = [ 'user' ]
const USER = gql `
query getMiniUser($name: String!) {
user(login: $name) {
login
id
isFollowingViewer
viewerIsFollowing
bio
avatarUrl
isViewer
url
followers(first:10) {
edges {
node {
login
avatarUrl
id
}
}
}
}
}
` ;
const endpoint = "https://api.github.com/graphql" ;
const headers = {
headers : {
Authorization : `Bearer ${ token + 'gg' } ` ,
"Content-Type" : "application/json" ,
} ,
} ;
const graphQLClient = new GraphQLClient ( endpoint , headers ) ;
const fetchData = async ( ) => await graphQLClient . request ( USER , { name :"tigawanna" } ) ;
const keyword = "a"
const query = useQuery ( key , fetchData ,
{
enabled : username . length > 3 ,
select : ( data :User ) => {
let newdata
if ( keyword ) {
const followers = data . user . followers . edges . filter ( ( item ) => {
return item . node . login . includes ( keyword )
} )
newdata = { ...data . user , followers}
return { user :newdata }
}
return data
} ,
onSuccess :( data :User ) => {
console . log ( "success" )
} ,
onError :( error :any ) => {
console . log ( "error = " , error . response )
if ( error ?. response ?. status === "401" || error ?. response ?. status === "402" ) {
// invalidate my locally stored token to send me back to
// login screen,those codes mean tokenhas an issue
}
}
}
)
console . log ( "test query === " , query . data )
return (
< div className = 'w-full h-full ' >
HELLO
< / div>
) ; }
import React from 'react'
import { useQuery } from 'react-query' ;
import { GraphQLClient } from 'graphql-request' ;
import { gql } from 'graphql-tag' ;
import { useInfiniteQuery } from 'react-query' ;
interface TestProps {
token :string
}
export interface RootResponse {
pages : Page [ ] ;
pageParams : any [ ] ;
}
export interface Page {
user : User ;
}
export interface User {
login : string ;
id : string ;
isFollowingViewer : boolean ;
viewerIsFollowing : boolean ;
bio : string ;
avatarUrl : string ;
isViewer : boolean ;
url : string ;
followers : Followers ;
}
export interface Followers {
edges : Edge [ ] ;
totalCount : number ;
pageInfo : PageInfo ;
}
export interface Edge {
node : Node ;
}
export interface Node {
login : string ;
avatarUrl : string ;
id : string ;
}
export interface PageInfo {
startCursor : string ;
endCursor : string ;
hasNextPage : boolean ;
hasPreviousPage : boolean ;
}
export const Test : React . FC < TestProps > = ( { token} ) => {
const username = 'tigawanna'
const key = [ 'user' ]
const USER = gql `
query getMiniUser($name: String!, $first: Int!, $after: String) {
user(login: $name) {
login
id
isFollowingViewer
viewerIsFollowing
bio
avatarUrl
isViewer
url
followers(first: $first, after: $after) {
edges {
node {
login
avatarUrl
id
}
}
totalCount
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
}
` ;
const endpoint = "https://api.github.com/graphql" ;
const headers = {
headers : {
Authorization : `Bearer ${ token } ` ,
"Content-Type" : "application/json" ,
} ,
} ;
const graphQLClient = new GraphQLClient ( endpoint , headers ) ;
const fetchData = async ( deps : any ) => {
const after = deps ?. pageParam ? deps . pageParam : null ;
return await graphQLClient . request ( USER , {
name : "tigawanna" ,
first : 10 ,
after,
} ) ;
} ;
const keyword = "a"
const query = useInfiniteQuery ( key , fetchData , {
enabled : username . length > 3 ,
onSuccess : ( data : RootResponse ) => {
console . log ( "success" , data ) ;
} ,
onError : ( error : any ) => {
console . log ( "error = " , error . response ) ;
if ( error ?. response ?. status === "401" || error ?. response ?. status === "402" ) {
// invalidate my locally stored token to send me back to
// login screen,those codes mean tokenhas an issue
}
} ,
getPreviousPageParam : ( firstPage : Page ) => {
return firstPage ?. user ?. followers ?. pageInfo ?. startCursor ?? null ;
} ,
getNextPageParam : ( lastPage : Page ) => {
return lastPage ?. user ?. followers ?. pageInfo ?. endCursor ?? null ;
} ,
} ) ;
console . log ( "test query === " , query . data )
const pages = query ?. data ?. pages ;
// console.log("followers === ",followers)
//@ts-ignore
const extras = pages [ pages . length - 1 ] . user ?. followers ;
const hasMore = extras ?. pageInfo ?. hasNextPage ;
return (
< div className = "w-full h-full " >
< div className = "h-fit w-full flex-center flex-wrap" >
{ pages ?. map ( ( page ) => {
return page ?. user ?. followers ?. edges ?. map ( ( item ) => {
return (
< div className = 'w-[30%] h-14 p-3 m-2 border border-green-500 ' >
user :{ item . node . login } < / div>
) ;
} ) ;
} ) }
< / div>
{ ! query . isFetchingNextPage && hasMore ? (
< button
className = "m-2 hover:text-purple-400 shadow-lg hover:shadow-purple"
onClick = { ( ) => {
query . fetchNextPage ( ) ;
} }
>
-- - load more -- -
< / button >
) : null }
{ query . isFetchingNextPage ? (
< div className = "w-full flex-center m-1 p-1" > loading more ...< / div>
) : null }
< / div >
) ; }
import React from 'react'
import { useQuery } from 'react-query' ;
import { GraphQLClient } from 'graphql-request' ;
import { gql } from 'graphql-tag' ;
import { useInfiniteQuery } from 'react-query' ;
interface TestProps {
token :string
}
export interface RootResponse {
pages : Page [ ] ;
pageParams : any [ ] ;
}
export interface Page {
user : User ;
}
export interface User {
login : string ;
id : string ;
isFollowingViewer : boolean ;
viewerIsFollowing : boolean ;
bio : string ;
avatarUrl : string ;
isViewer : boolean ;
url : string ;
followers : Followers ;
}
export interface Followers {
edges : Edge [ ] ;
totalCount : number ;
pageInfo : PageInfo ;
}
export interface Edge {
node : Node ;
}
export interface Node {
login : string ;
avatarUrl : string ;
id : string ;
}
export interface PageInfo {
startCursor : string ;
endCursor : string ;
hasNextPage : boolean ;
hasPreviousPage : boolean ;
}
export const Test : React . FC < TestProps > = ( { token} ) => {
const username = 'tigawanna'
const key = [ 'user' ]
const USER = gql `
query getMiniUser($name: String!, $first: Int!, $after: String) {
user(login: $name) {
login
id
isFollowingViewer
viewerIsFollowing
bio
avatarUrl
isViewer
url
followers(first: $first, after: $after) {
edges {
node {
login
avatarUrl
id
}
}
totalCount
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
}
` ;
const endpoint = "https://api.github.com/graphql" ;
const headers = {
headers : {
Authorization : `Bearer ${ token } ` ,
"Content-Type" : "application/json" ,
} ,
} ;
const graphQLClient = new GraphQLClient ( endpoint , headers ) ;
// const fetchData = async () => await graphQLClient.request(USER,{name:"tigawanna",
// first:10,after:null
// });
const fetchData = async ( deps : any ) => {
const after = deps ?. pageParam ? deps . pageParam : null ;
return await graphQLClient . request ( USER , {
name : "tigawanna" ,
first : 10 ,
after,
} ) ;
} ;
const keyword = "a"
const query = useInfiniteQuery ( key , fetchData , {
enabled : username . length > 3 ,
select :( data :RootResponse ) => {
return concatFollowerPages ( data , "" )
} ,
onSuccess : ( data : RootResponse ) => {
// console.log("success", data);
} ,
onError : ( error : any ) => {
console . log ( "error = " , error . response ) ;
if ( error ?. response ?. status === "401" || error ?. response ?. status === "402" ) {
// invalidate my locally stored token to send me back to
// login screen,those codes mean tokenhas an issue
}
} ,
getPreviousPageParam : ( firstPage : Page ) => {
return firstPage ?. user ?. followers ?. pageInfo ?. startCursor ?? null ;
} ,
getNextPageParam : ( lastPage : Page ) => {
console . log ( "end cursor " , lastPage ?. user ?. followers ?. pageInfo ?. endCursor ) ;
return lastPage ?. user ?. followers ?. pageInfo ?. endCursor ?? null ;
} ,
} ) ;
// console.log("test query === ",query.data)
if ( query . isFetching ) {
return < div > loading .... < / div>
}
const pages = query ?. data ?. pages ;
return (
< div className = "w-full h-full " >
< div className = "h-fit w-full flex-center flex-wrap" >
{ pages ?. map ( ( page ) => {
return page ?. user ?. followers ?. edges ?. map ( ( item , index ) => {
return (
< div
key = { item . node . id }
className = "w-[30%] h-14 p-3 m-2 border border-green-500 text-lg font-bold"
>
{ index } { item . node . login }
< / div >
) ;
} ) ;
} ) }
< / div>
{ ! query . isFetchingNextPage &&
query ?. data ?. pages [ 0 ] ?. user ?. followers ?. pageInfo ?. hasNextPage ? (
< button
className = "m-2 hover:text-purple-400 shadow-lg hover:shadow-purple"
onClick = { ( ) => {
query . fetchNextPage ( ) ;
} }
>
-- - load more -- -
< / button >
) : null }
{ query . isFetchingNextPage ? (
< div className = "w-full flex-center m-1 p-1" > loading more ...< / div>
) : null }
< / div >
) ; }
export const concatFollowerPages = ( data : RootResponse , keyword : string ) => {
let totalRepos = data . pages [ 0 ] . user . followers . edges ;
let i = 1 ;
for ( i = 1 ; i < data . pages . length ; i ++ ) {
if ( data ?. pages ) {
totalRepos = [ ...totalRepos , ...data . pages [ i ] . user . followers . edges ] ;
}
}
const filtered = totalRepos . filter ( ( item ) =>
item . node . login . toLowerCase ( ) . includes ( keyword . toLowerCase ( ) )
) ;
const base = data . pages [ data . pages . length - 1 ] . user ;
const user = {
...base ,
login : base . login ,
followers : {
edges : filtered ,
totalCount : base . followers . totalCount ,
pageInfo : base . followers . pageInfo ,
} ,
} ;
const final :RootResponse = {
pageParams : [ ...data . pageParams ] ,
pages : [ { user : user } ] ,
} ;
return final ;
} ;