React – How to use react-query?

How to install & configure

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
yarn add react-query
yarn add react-query
yarn add react-query
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const RootComponent = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: true, // React Query automatically requests fresh data for you in the background
},
},
})
return (<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>)
}
ReactDOM.render(<RootComponent />, document.getElementById('root'))
const RootComponent = () => { const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: true, // React Query automatically requests fresh data for you in the background }, }, }) return (<QueryClientProvider client={queryClient}> <App /> </QueryClientProvider>) } ReactDOM.render(<RootComponent />, document.getElementById('root'))
const RootComponent = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        refetchOnWindowFocus: true, // React Query automatically requests fresh data for you in the background
      },
    },
  })

  return (<QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>)
}

ReactDOM.render(<RootComponent />, document.getElementById('root'))

Add devtools

By default, React Query Devtools are not included in production bundles when process.env.NODE_ENV === 'production', so you don’t need to worry about excluding them during a production build.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
...
import { ReactQueryDevtools } from 'react-query/devtools'
const Bootstrap = () => {
...
return (
...
<App />
<ReactQueryDevtools initialIsOpen={false} />
...
)
}
ReactDOM.render(<RootComponent />, document.getElementById('root'))
... import { ReactQueryDevtools } from 'react-query/devtools' const Bootstrap = () => { ... return ( ... <App /> <ReactQueryDevtools initialIsOpen={false} /> ... ) } ReactDOM.render(<RootComponent />, document.getElementById('root'))
...

import { ReactQueryDevtools } from 'react-query/devtools'

const Bootstrap = () => {
  ...
  return (
        ...
        <App />
        <ReactQueryDevtools initialIsOpen={false} />
        ...
  )
}

ReactDOM.render(<RootComponent />, document.getElementById('root'))

How to request Rest API?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { useQuery } from 'react-query';
import axios from 'axios';
export const fetchPosts = async () => {
const { data } = await axios.get(
'https://jsonplaceholder.typicode.com/comments?postId=5'
);
return data;
};
const useFetchPosts = () => useQuery(['fetchPosts'], () => fetchPosts());
export default useFetchPosts;
import { useQuery } from 'react-query'; import axios from 'axios'; export const fetchPosts = async () => { const { data } = await axios.get( 'https://jsonplaceholder.typicode.com/comments?postId=5' ); return data; }; const useFetchPosts = () => useQuery(['fetchPosts'], () => fetchPosts()); export default useFetchPosts;
import { useQuery } from 'react-query';
import axios from 'axios';

export const fetchPosts = async () => {
  const { data } = await axios.get(
    'https://jsonplaceholder.typicode.com/comments?postId=5'
  );
  return data;
};

const useFetchPosts = () => useQuery(['fetchPosts'], () => fetchPosts());

export default useFetchPosts;
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const Home: FC<Props> = ({ navigation }) => {
const { data, isLoading, isSuccess } = useFetchPosts();
if (isLoading) {
console.log('=========isLoading', isLoading);
}
if (data) {
console.log('=========data', data);
}
if (isSuccess) {
console.log('=========isSuccess', isSuccess);
}
return (...)
});
const Home: FC<Props> = ({ navigation }) => { const { data, isLoading, isSuccess } = useFetchPosts(); if (isLoading) { console.log('=========isLoading', isLoading); } if (data) { console.log('=========data', data); } if (isSuccess) { console.log('=========isSuccess', isSuccess); } return (...) });
const Home: FC<Props> = ({ navigation }) => {
  const { data, isLoading, isSuccess } = useFetchPosts();

  if (isLoading) {
    console.log('=========isLoading', isLoading);
  }

  if (data) {
    console.log('=========data', data);
  }

  if (isSuccess) {
    console.log('=========isSuccess', isSuccess);
  }

  return (...)
});

How to request graphQL?

Install

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
yarn add graphql graphql-request
yarn add graphql graphql-request
yarn add graphql graphql-request

Usage 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// queries.js
import { gql } from 'graphql-request'
export const ONE_GRAPHQL_QUERY = gql`
query getPost($postId: ID!) {
getPost(_id: $postId) {
_id
content
description
title
}
}
`
// queries.js import { gql } from 'graphql-request' export const ONE_GRAPHQL_QUERY = gql` query getPost($postId: ID!) { getPost(_id: $postId) { _id content description title } } `
// queries.js

import { gql } from 'graphql-request'

export const ONE_GRAPHQL_QUERY = gql`
  query getPost($postId: ID!) {
    getPost(_id: $postId) {
      _id
      content
      description
      title
    }
  }
`
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const graphQLClient = new GraphQLClient('https://graphql.abcd.com/', {
method: 'POST',
headers: {
'x-api-key': xxxxxxxxxx,
'content-type': 'application/json',
},
})
/////////////////////
/////////////////////
export const fetchPost = async (postId) => {
const response = await graphQLClient.request(ONE_GRAPHQL_QUERY, {
id: postId,
})
return response
}
const graphQLClient = new GraphQLClient('https://graphql.abcd.com/', { method: 'POST', headers: { 'x-api-key': xxxxxxxxxx, 'content-type': 'application/json', }, }) ///////////////////// ///////////////////// export const fetchPost = async (postId) => { const response = await graphQLClient.request(ONE_GRAPHQL_QUERY, { id: postId, }) return response }
const graphQLClient = new GraphQLClient('https://graphql.abcd.com/', {
  method: 'POST',
  headers: {
    'x-api-key': xxxxxxxxxx,
    'content-type': 'application/json',
  },
})

/////////////////////
/////////////////////

export const fetchPost = async (postId) => {
  const response = await graphQLClient.request(ONE_GRAPHQL_QUERY, {
    id: postId,
  })
  return response
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const Demo = ({ postId }) => {
const { data, isLoading, error } = useQuery(
['fetchPost', postId],
() => fetchPost(postId)
)
if (data) {
console.log(data)
}
return (
<div>{isLoading ? 'Loading...' : 'Done!'}</div>
)
}
export default Demo
const Demo = ({ postId }) => { const { data, isLoading, error } = useQuery( ['fetchPost', postId], () => fetchPost(postId) ) if (data) { console.log(data) } return ( <div>{isLoading ? 'Loading...' : 'Done!'}</div> ) } export default Demo
const Demo = ({ postId }) => {
  const { data, isLoading, error } = useQuery(
    ['fetchPost', postId],
    () => fetchPost(postId)
  )

  if (data) {
    console.log(data)
  }

  return (
      <div>{isLoading ? 'Loading...' : 'Done!'}</div>
  )
}

export default Demo

How to trigger a fetch request with a button?

  • Use refetch()
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const { refetch: fetchSomething } = useQuery(
['fetchMyData', input],
() => fetchMyData(input),
{
enabled: false,
}
)
function onClick(e) {
fetchSomething()
}
const { refetch: fetchSomething } = useQuery( ['fetchMyData', input], () => fetchMyData(input), { enabled: false, } ) function onClick(e) { fetchSomething() }
const { refetch: fetchSomething } = useQuery(
  ['fetchMyData', input],
  () => fetchMyData(input),
  {
    enabled: false,
  }
)

function onClick(e) {
  fetchSomething()
}

How to trigger create/ update/ delete data with a button?

  • Method 1
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { GraphQLClient } from 'graphql-request'
import { useMutation } from 'react-query'
const graphQLClient = new GraphQLClient(
process.env.API_GRAPHQL_ENDPOINT,
{
method: 'GET',
headers: {
Authorization: accessToken,
},
}
)
const updateUser = async (input) => {
const response = await graphQLClient.request(UPDATE_USER_QUERY, {
input,
})
return response
}
export const useUpdateUser = () => {
return useMutation(
async (data) => {
return await updateUser(data)
},
{
onMutate: (editedValue) => {
// console.log(data, error, editedValue)
},
onError: (error, editedValue) => {
console.log(error, editedValue)
},
onSettled: (data, error, editedValue) => {
// console.log(data, error, editedValue)
},
onSuccess: (data, variables) => {
// console.log(data, variables)
},
}
)
}
import { GraphQLClient } from 'graphql-request' import { useMutation } from 'react-query' const graphQLClient = new GraphQLClient( process.env.API_GRAPHQL_ENDPOINT, { method: 'GET', headers: { Authorization: accessToken, }, } ) const updateUser = async (input) => { const response = await graphQLClient.request(UPDATE_USER_QUERY, { input, }) return response } export const useUpdateUser = () => { return useMutation( async (data) => { return await updateUser(data) }, { onMutate: (editedValue) => { // console.log(data, error, editedValue) }, onError: (error, editedValue) => { console.log(error, editedValue) }, onSettled: (data, error, editedValue) => { // console.log(data, error, editedValue) }, onSuccess: (data, variables) => { // console.log(data, variables) }, } ) }
import { GraphQLClient } from 'graphql-request'
import { useMutation } from 'react-query'

const graphQLClient = new GraphQLClient(
  process.env.API_GRAPHQL_ENDPOINT,
  {
    method: 'GET',
    headers: {
      Authorization: accessToken,
    },
  }
)

const updateUser = async (input) => {
  const response = await graphQLClient.request(UPDATE_USER_QUERY, {
    input,
  })
  return response
}

export const useUpdateUser = () => {
  return useMutation(
    async (data) => {
      return await updateUser(data)
    },
    {
      onMutate: (editedValue) => {
        // console.log(data, error, editedValue)
      },
      onError: (error, editedValue) => {
        console.log(error, editedValue)
      },
      onSettled: (data, error, editedValue) => {
        // console.log(data, error, editedValue)
      },
      onSuccess: (data, variables) => {
        // console.log(data, variables)
      },
    }
  )
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Use it in your component
const {
mutateAsync: updateUser,
status: userUpdateStatus,
isLoading: isLoadingUserUpdate,
data: userUpdateData,
error: userUpdateErr
} = useUpdateNote()
function onClickSaveUser() {
const detail = getUserDetail(...)
updateUser(detail)
}
// Use it in your component const { mutateAsync: updateUser, status: userUpdateStatus, isLoading: isLoadingUserUpdate, data: userUpdateData, error: userUpdateErr } = useUpdateNote() function onClickSaveUser() { const detail = getUserDetail(...) updateUser(detail) }
// Use it in your component

const {
  mutateAsync: updateUser,
  status: userUpdateStatus,
  isLoading: isLoadingUserUpdate,
  data: userUpdateData,
  error: userUpdateErr
} = useUpdateNote()

function onClickSaveUser() {
  const detail = getUserDetail(...)
  updateUser(detail)
}

graphql-hasura-with-react-query-mutation

  • Method 2
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
export const updateUserNote = async (input) => {
const response = await graphQLClient.request(UPDATE_USER_QUERY, {
input,
})
return response
}
export const updateUserNote = async (input) => { const response = await graphQLClient.request(UPDATE_USER_QUERY, { input, }) return response }
export const updateUserNote = async (input) => {
  const response = await graphQLClient.request(UPDATE_USER_QUERY, {
    input,
  })
  return response
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const mutation = useMutation(async (note) => {
return await updateBlackbookNote(note)
})
function onClickSaveUser() {
const detail = getUserDetail(...)
mutation.mutate(detail)
}
const mutation = useMutation(async (note) => { return await updateBlackbookNote(note) }) function onClickSaveUser() { const detail = getUserDetail(...) mutation.mutate(detail) }
const mutation = useMutation(async (note) => {
  return await updateBlackbookNote(note)
})

function onClickSaveUser() {
  const detail = getUserDetail(...)
  mutation.mutate(detail)
}

react-query.tanstack.com/guides/mutations

How to save fetched data into useState?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const YourComponent = () => {
const [userList, setUserList] = useState(null)
const { isLoading } = useQuery(
['fetchUserList'],
() => fetchUserList(),
{
onSuccess: (data) => {
setUserList(data)
},
}
)
...
const YourComponent = () => { const [userList, setUserList] = useState(null) const { isLoading } = useQuery( ['fetchUserList'], () => fetchUserList(), { onSuccess: (data) => { setUserList(data) }, } ) ...
const YourComponent = () => {
  const [userList, setUserList] = useState(null)

  const { isLoading } = useQuery(
    ['fetchUserList'],
    () => fetchUserList(),
    {
      onSuccess: (data) => {
        setUserList(data)
      },
    }
  )

...

How to request paginated queries?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function Todos() {
const [nextPageParam, setNextPageParam] = React.useState(0)
const fetchProjects = (nextPageParam = 0) => fetch('/api/projects?page=' + nextPageParam).then((res) => res.json())
const {
isLoading,
isError,
error,
data,
isFetching,
isPreviousData,
} = useQuery(['projects', nextPageParam], () => fetchProjects(nextPageParam), { keepPreviousData : true })
return (
<div>
{isLoading ? (
<div>Loading...</div>
) : isError ? (
<div>Error: {error.message}</div>
) : (
<div>
{data.projects.map(project => (
<p key={project.id}>{project.name}</p>
))}
</div>
)}
{/* Pages */}
<span>Current Page: {nextPageParam + 1}</span>
<button
onClick={() => setNextPageParam(old => Math.max(old - 1, 0))}
disabled={nextPageParam === 0}
>
Previous Page
</button>{' '}
<button
onClick={() => {
if (!isPreviousData && data.hasMore) {
setNextPageParam(old => old + 1)
}
}}
// Disable the Next Page button until we know a next page is available
disabled={isPreviousData || !data?.hasMore}
>
Next Page
</button>
{isFetching ? <span> Loading...</span> : null}{' '}
</div>
)
}
function Todos() { const [nextPageParam, setNextPageParam] = React.useState(0) const fetchProjects = (nextPageParam = 0) => fetch('/api/projects?page=' + nextPageParam).then((res) => res.json()) const { isLoading, isError, error, data, isFetching, isPreviousData, } = useQuery(['projects', nextPageParam], () => fetchProjects(nextPageParam), { keepPreviousData : true }) return ( <div> {isLoading ? ( <div>Loading...</div> ) : isError ? ( <div>Error: {error.message}</div> ) : ( <div> {data.projects.map(project => ( <p key={project.id}>{project.name}</p> ))} </div> )} {/* Pages */} <span>Current Page: {nextPageParam + 1}</span> <button onClick={() => setNextPageParam(old => Math.max(old - 1, 0))} disabled={nextPageParam === 0} > Previous Page </button>{' '} <button onClick={() => { if (!isPreviousData && data.hasMore) { setNextPageParam(old => old + 1) } }} // Disable the Next Page button until we know a next page is available disabled={isPreviousData || !data?.hasMore} > Next Page </button> {isFetching ? <span> Loading...</span> : null}{' '} </div> ) }
function Todos() {
   const [nextPageParam, setNextPageParam] = React.useState(0)
 
   const fetchProjects = (nextPageParam = 0) => fetch('/api/projects?page=' + nextPageParam).then((res) => res.json())
 
   const {
     isLoading,
     isError,
     error,
     data,
     isFetching,
     isPreviousData,
   } = useQuery(['projects', nextPageParam], () => fetchProjects(nextPageParam), { keepPreviousData : true })
 
   return (
     <div>
       {isLoading ? (
         <div>Loading...</div>
       ) : isError ? (
         <div>Error: {error.message}</div>
       ) : (
         <div>
           {data.projects.map(project => (
             <p key={project.id}>{project.name}</p>
           ))}
         </div>
       )}

       {/* Pages */}
       <span>Current Page: {nextPageParam + 1}</span>
       <button
         onClick={() => setNextPageParam(old => Math.max(old - 1, 0))}
         disabled={nextPageParam === 0}
       >
         Previous Page
       </button>{' '}
       <button
         onClick={() => {
           if (!isPreviousData && data.hasMore) {
             setNextPageParam(old => old + 1)
           }
         }}
         // Disable the Next Page button until we know a next page is available
         disabled={isPreviousData || !data?.hasMore}
       >
         Next Page
       </button>
       {isFetching ? <span> Loading...</span> : null}{' '}
     </div>
   )
 }

How to request infinite queries?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { useInfiniteQuery } from 'react-query'
const fetchProjects = (customParam, queryParam) =>
fetch('/api/projects?cursor=' + queryParam + '?category=' + customParam)
function Projects({ customParam }) {
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
status,
} = useInfiniteQuery('projects', ({ pageParam: queryParam }) => {
// "pageParam" is returned from the "getNextParam"
return fetchProjects(customParam, queryParam)
},
{
getNextPageParam: (lastPage, pages) => {
const queryParam = lastPage.nextCursor
// If no key is returned from last data, "false": no next page
return queryParam ? queryParam : false
},
})
return status === 'loading' ? (
<p>Loading...</p>
) : status === 'error' ? (
<p>Error: {error.message}</p>
) : (
<>
{data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.projects.map(project => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? 'Loading more...'
: hasNextPage
? 'Load More'
: 'Nothing more to load'}
</button>
</div>
<div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
</>
)
}
import { useInfiniteQuery } from 'react-query' const fetchProjects = (customParam, queryParam) => fetch('/api/projects?cursor=' + queryParam + '?category=' + customParam) function Projects({ customParam }) { const { data, error, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage, status, } = useInfiniteQuery('projects', ({ pageParam: queryParam }) => { // "pageParam" is returned from the "getNextParam" return fetchProjects(customParam, queryParam) }, { getNextPageParam: (lastPage, pages) => { const queryParam = lastPage.nextCursor // If no key is returned from last data, "false": no next page return queryParam ? queryParam : false }, }) return status === 'loading' ? ( <p>Loading...</p> ) : status === 'error' ? ( <p>Error: {error.message}</p> ) : ( <> {data.pages.map((group, i) => ( <React.Fragment key={i}> {group.projects.map(project => ( <p key={project.id}>{project.name}</p> ))} </React.Fragment> ))} <div> <button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage} > {isFetchingNextPage ? 'Loading more...' : hasNextPage ? 'Load More' : 'Nothing more to load'} </button> </div> <div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div> </> ) }
import { useInfiniteQuery } from 'react-query'

const fetchProjects = (customParam, queryParam) =>
  fetch('/api/projects?cursor=' + queryParam + '?category=' + customParam)

 
function Projects({ customParam }) { 
   const {
     data,
     error,
     fetchNextPage,
     hasNextPage,
     isFetching,
     isFetchingNextPage,
     status,
   } = useInfiniteQuery('projects', ({ pageParam: queryParam }) => { 

     // "pageParam" is returned from the "getNextParam"
     return fetchProjects(customParam, queryParam)
   },
   {
     getNextPageParam: (lastPage, pages) => {
       const queryParam = lastPage.nextCursor
       
       // If no key is returned from last data, "false": no next page
       return queryParam ? queryParam : false
     },
   })
 
   return status === 'loading' ? (
     <p>Loading...</p>
   ) : status === 'error' ? (
     <p>Error: {error.message}</p>
   ) : (
     <>
       {data.pages.map((group, i) => (
         <React.Fragment key={i}>
           {group.projects.map(project => (
             <p key={project.id}>{project.name}</p>
           ))}
         </React.Fragment>
       ))}
       <div>
         <button
           onClick={() => fetchNextPage()}
           disabled={!hasNextPage || isFetchingNextPage}
         >
           {isFetchingNextPage
             ? 'Loading more...'
             : hasNextPage
             ? 'Load More'
             : 'Nothing more to load'}
         </button>
       </div>
       <div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
     </>
   )
 }

What the difference between react-query and apolloClient?

react-query doesn’t have normalized cache.

A “fully normalized cache” means that if multiple different queries return the same type of item with the same ID, it will only be stored once.

As an example, say you have a blog post app with /getPosts and /getPost/:postId endpoints. You make a request to /getPosts, and also to /getPost/3. Both endpoints return an item with {id: 3}. Do you end up with one object in the cache with that ID, or two objects in different places?

With a normalized cache, the client determines that “both of these items are of type Post, and both are ID 3″, so it only saves the one copy. With a non-normalized cache, the array of [{id: 1}, {id: 2}, {id: 3}] from /getPosts is saved separately from the {id: 3} returned by /getPost/3.

How to use json-server to simulate fake API call?

Install

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo npm install -g json-server
sudo npm install -g json-server
sudo npm install -g json-server

Create fake response db.json

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
{ "posts": [ { "id": 1, "title": "json-server", "author": "typicode" } ], "comments": [ { "id": 1, "body": "some comment", "postId": 1 } ], "profile": { "name": "typicode" } }
{
  "posts": [
    { "id": 1, "title": "json-server", "author": "typicode" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}

Simulate fake API call

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
json-server --watch db.json --port 9000
json-server --watch db.json --port 9000
json-server --watch db.json --port 9000

Be the first to comment

Leave a Reply

Your email address will not be published.


*