How to install & configure
yarn add react-query
const RootComponent = () => {
const queryClient = new QueryClient({
refetchOnWindowFocus: true, // React Query automatically requests fresh data for you in the background
return (<QueryClientProvider client={queryClient}>
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.
import { ReactQueryDevtools } from 'react-query/devtools'
const Bootstrap = () => {
<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?
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'
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;
const Home: FC<Props> = ({ navigation }) => {
const { data, isLoading, isSuccess } = useFetchPosts();
console.log('=========isLoading', isLoading);
console.log('=========data', data);
console.log('=========isSuccess', isSuccess);
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
yarn add graphql graphql-request
yarn add graphql graphql-request
yarn add graphql graphql-request
Usage 1
import { gql } from 'graphql-request'
export const ONE_GRAPHQL_QUERY = gql`
query getPost($postId: ID!) {
// 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
}
}
`
const graphQLClient = new GraphQLClient('https://graphql.abcd.com/', {
'content-type': 'application/json',
export const fetchPost = async (postId) => {
const response = await graphQLClient.request(ONE_GRAPHQL_QUERY, {
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 Demo = ({ postId }) => {
const { data, isLoading, error } = useQuery(
<div>{isLoading ? 'Loading...' : 'Done!'}</div>
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?
const { refetch: fetchSomething } = useQuery(
() => fetchMyData(input),
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?
import { GraphQLClient } from 'graphql-request'
import { useMutation } from 'react-query'
const graphQLClient = new GraphQLClient(
process.env.API_GRAPHQL_ENDPOINT,
Authorization: accessToken,
const updateUser = async (input) => {
const response = await graphQLClient.request(UPDATE_USER_QUERY, {
export const useUpdateUser = () => {
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)
},
}
)
}
// Use it in your component
status: userUpdateStatus,
isLoading: isLoadingUserUpdate,
function onClickSaveUser() {
const detail = getUserDetail(...)
// 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
export const updateUserNote = async (input) => {
const response = await graphQLClient.request(UPDATE_USER_QUERY, {
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
}
const mutation = useMutation(async (note) => {
return await updateBlackbookNote(note)
function onClickSaveUser() {
const detail = getUserDetail(...)
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?
const YourComponent = () => {
const [userList, setUserList] = useState(null)
const { isLoading } = useQuery(
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?
const [nextPageParam, setNextPageParam] = React.useState(0)
const fetchProjects = (nextPageParam = 0) => fetch('/api/projects?page=' + nextPageParam).then((res) => res.json())
} = useQuery(['projects', nextPageParam], () => fetchProjects(nextPageParam), { keepPreviousData : true })
<div>Error: {error.message}</div>
{data.projects.map(project => (
<p key={project.id}>{project.name}</p>
<span>Current Page: {nextPageParam + 1}</span>
onClick={() => setNextPageParam(old => Math.max(old - 1, 0))}
disabled={nextPageParam === 0}
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}
{isFetching ? <span> Loading...</span> : null}{' '}
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?
import { useInfiniteQuery } from 'react-query'
const fetchProjects = (customParam, queryParam) =>
fetch('/api/projects?cursor=' + queryParam + '?category=' + customParam)
function Projects({ customParam }) {
} = 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' ? (
) : status === 'error' ? (
<p>Error: {error.message}</p>
{data.pages.map((group, i) => (
{group.projects.map(project => (
<p key={project.id}>{project.name}</p>
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
: 'Nothing more to load'}
<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
sudo npm install -g json-server
sudo npm install -g json-server
sudo npm install -g json-server
Create fake response db.json
{ "id": 1, "title": "json-server", "author": "typicode" }
{ "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
json-server --watch db.json --port 9000
json-server --watch db.json --port 9000
json-server --watch db.json --port 9000
Leave a Reply